1、前言
虽然有了解kotlin,但是一直没在项目中使用,最近为了学习Jetpack+组件化,新开了个练习项目,顺便学一下kotlin,记录下学习路线。
2、学习路线
2.1、语言学习
主要学一下基本语法:
官方中文文档:https://www.kotlincn.net/docs/reference/
2.2、Android中的学习
kotlin在android中的使用:
google官方文档:https://developer.android.google.cn/kotlin/add-kotlin
看完差不多够用了
2.3、协程
协程可以用同步的方式编写异步的代码(减少回调),在Android中如网络请求,文件io,数据库等。协程比线程更轻量,线程是全局的,但是协程可以指定作用域,在Android中利用viewModelScope或者lifecycleScope可以感知activity生命周期,并自动取消协程。
viewModelScope.launch{
//主线程启动一个协程
val data = repository.fetchData() //网络请求
//更新UI
textView.text = data.title
}
更多可以参考google开源项目:sunflower
2.4、扩展函数
kotlin提供了很多扩展函数,比如apply、run等,也可以自定义,如
/**
* 图片加载扩展方法
*/
fun ImageView.load(url: String) {
Glide.with(this)
.load(url)
.into(this)
}
imageView.load("http://xxxxx.png")
/**
* 根据手机的分辨率将dp转成为px。
*/
val Float.dp2px
get() = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
this,
Resources.getSystem().displayMetrics
)
//使用
20f.dp2px
3、网络请求简单封装
3.1、封装响应类
/**
* 用密封类sealed封装响应数据类
*/
sealed class ApiResult<out T : Any> {
//获取数据成功
data class Success<out T : Any>(val data: T) : ApiResult<T>()
//失败
data class Error(val exception: Exception) : ApiResult<Nothing>()
}
//请求数据
viewModelScope.launch{
//主线程启动一个协程
try{
val data = repository.fetchData() //网络请求
//更新UI
textView.text = data.data.title
} catch(e : Exception){
//请求失败
...
}
}
3.2、统一处理异常
对于每个网络请求,显然不能每个都加异常处理,可以通过高阶函数,统一处理异常。(高阶函数:一个函数可以将另一个函数当作参数)
/**
* 统一处理网络请求异常
* [call]:网络请求方法:suspend方法,返回数据类型为泛型T
* [errorMsg]:错误信息
* 返回类型:ApiResult<T> 可能为Success也可能为Error
*/
suspend fun <T : Any> request(call: suspend () -> T, errorMsg: String): ApiResult<T> =
try {
//请求成功
ApiResult.Success(call())
} catch (e: Exception) {
//请求失败
ApiResult.Error(Exception(errorMsg, e).also { e.printStackTrace() })
}
//请求数据
/**
* 三者关系:ViewModel持有Repository,Repository持有ApiService,ApiService执行网络请求
*/
//retrofit网络请求接口
interface Api {
/**
* 获取数据
*/
@GET
suspend fun fetchData(@Url url: String = "http://xxx"): Data
}
//repository类
class Repository() {
/**
* 获取数据
*/
suspend fun fetchData() =
request(call = {
//网络请求
apiService.fetchData()
}, errorMsg = "请求失败")
}
//viewModel类
viewModelScope.launch{
//主线程启动一个协程
val data = repository.fetchData() //网络请求
when(data){
is ApiResult.Success ->{ //更新Ui ,或者封装成LiveData发送数据
textView.text= data.data.title
}
is ApiResult.Error ->{ //错误提示
data.exception.print()
}
}
}
4、网络请求简单封装(flow篇)
如果用flow,可以以更简单的方式封装
// 添加个顶级函数
fun <T : Any> requestFlow(
call: suspend () -> T,
onSuccess: (T) -> Unit,
onStart: () -> Unit = {},
onComplete: () -> Unit = {},
onError: (Throwable) -> Unit = {}
) = flow {
emit(call())
}.flowOn(Dispatchers.IO) // 在子线程执行
.onStart {
onStart()
}.catch { ex ->
onError(ex)
}.onCompletion {
onComplete()
}.onEach { // 分离消费
onSuccess(it)
}
// 使用
override fun fetchData() {
requestFlow({
// 网络请求
repository.fetchData()
}, { // 请求成功
_discoveryData.value = it
}, onStart = { // 请求开始
_onRefreshing.value = true
_onError.value = false
}, onComplete = { // 请求完毕
_onRefreshing.value = false
}, onError = { // 请求失败
_onError.value = true
}).launchIn(viewModelScope)
}
完