【Jetpack篇】协程,嵌入式工程师面试自我介绍

abstract class BaseFragment<T : ViewDataBinding, VM : BaseViewModel> : Fragment(){

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mViewModel = getViewModel()

mViewModel?.errorLiveData?.observe(viewLifecycleOwner, Observer {
Log.d(TAG, "onViewCreated: error ")
showError()
throwableHandler(it)
})
}
}

每个子Fragment只需要继承BaseFragment即可,具体的异常监听就不用开发者管理。

2、 [Loading状态]

除了异常状态外,请求必不可少的就是Loading,这里Loading分为两种,一种是整个页面替换为Loading,例如Recyclerview列表时,就可以直接整个页面先Loading,而后显示数据;还有一种是数据界面不替换,只是个Loading Dialog显示在上层,例如点击登录时,需要一个loading。

Loading和异常处理的思路一致,可以在BaseViewModel中添加一个LoadingLiveData,数据类型为Boolean,在每个请求一开始LoadingLiveData.postValue(true),结束请求或者请求异常时,就LoadingLiveData.postValue(false)。UI层BaseFragment中,则可以监听LoadingLiveData发出的是true还是false,以便对Loading的显示和隐藏进行控制。

ViewModel层:

open class BaseViewModel : ViewModel() {
//加载中
val loadingLiveData = SingleLiveData()
//异常
val errorLiveData = SingleLiveData()

fun launch(
block: suspend () -> Unit,
error: suspend (Throwable) -> Unit,
complete: suspend () -> Unit
) {
loadingLiveData.postValue(true)
viewModelScope.launch(Dispatchers.IO) {
try {
block()
} catch (e: Exception) {
Log.d(TAG, "launch: error ")
error(e)
} finally {
complete()
}
}
}
}

在BaseViewModel 中launch一开始就通知Loading显示,在try-catch-finally代码块的finally中将请求结束的通知分发出去。

UI层:

abstract class BaseFragment<T : ViewDataBinding, VM : BaseViewModel> : Fragment(){

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mViewModel = getViewModel()
//Loading 显示隐藏的监听
mViewModel?.loadingLiveData?.observe(viewLifecycleOwner, Observer {
if (it) {
//show loading
showLoading()
} else {

dismissLoading()
}
})

//请求异常的监听
mViewModel?.errorLiveData?.observe(viewLifecycleOwner, Observer {
Log.d(TAG, "onViewCreated: error ")
showError()
throwableHandler(it)
})
}
}

注册一个loading的观察者,当通知为true时,显示loading,false则隐藏。

3、 [Empty状态]

数据为空的状态发生在请求成功后,对于这种情况,可以直接在UI层中,请求成功的监听中对数据是否为null进行判断。

到这里,网络请求的基本封装已经完成,但是在运行测试的过程中,存在几个问题需要去解决,例如网络不通的情况下try-catch却不会抛出异常。接下来就开始进行二次封装。

暴露问题二次封装

问题一:网络请求异常,try-catch却不会将异常抛出

因为业务场景比较复杂,只依赖try-catch来获取异常,明显也会有所遗漏,那这种情况下我们可以直接以服务器返回的code,作为请求状态的依据。以上面Wanandroid的api为例,当errorCode=0时,则表示请求成功,其他的值都表示失败,那这就好办了。

我们新建一个密封类ResState,存放Success和Error状态,

sealed class ResState {
data class Success(val data: T) : ResState()
data class Error(val exception: Exception) : ResState()
}

对Repository层请求返回的数据进行code判断处理,新建一个BaseRepository类,

open class BaseRepository() {

suspend fun executeResp(
resp: BaseResp, successBlock: (suspend CoroutineScope.() -> Unit)? = null,
errorBlock: (suspend CoroutineScope.() -> Unit)? = null
): ResState {
return coroutineScope {
if (resp.errorCode == 0) {
successBlock?.let { it() }
ResState.Success(resp.data)
} else {
Log.d(TAG, “executeResp: error”)
errorBlock?.let { it() }
ResState.Error(IOException(resp.errorMsg))
}
}
}

}

errorCode == 0时,将ResState置为Success并将数据返回,errorCode !=0时,则将状态置为Error并将Exception返回。而子Repository则只需要继承BaseRepository即可,

class ProjectRepo : BaseRepository() {

suspend fun loadProjectTree(): ResState<List> {
return executeResp(mService.loadProjectTree())
}

修改后返回值用ResState<>包裹,并直接将请求的结果传给executeResp()方法,而ViewModel中也做出相应的修改,

class ProjectViewModel : BaseViewModel() {
val mProjectTreeLiveData = MutableLiveData<List>()

fun loadProjectTree() {
launch(
{
val state = mRepo.loadProjectTree()
//添加ResState判断
if (state is ResState.Success) {
mProjectTreeLiveData.postValue(state.data)
} else if (state is ResState.Error) {
Log.d(TAG, “loadProjectTree: ResState.Error”)
errorLiveData.postValue(state.exception)
}
},
{
errorLiveData.postValue(it)
},
{
loadingLiveData.postValue(false)
}
)
}
}

ViewModel层新增了一个ResState判断,通过请求的返回值ResState,如果是ResState.Success则将数据通知给UI,如果是ResState.Error,则将异常通知给UI。

服务器返回的code值进行判断,无疑是最准确的。

问题二:errorLiveData注册观察者一次后,不管请求失败还是成功,它还是会收到通知。

这是MutableLiveData的一个特性,只要当注册的观察者处于前台时,都会收到通知。那这个特性又影响了什么呢? 我在errorLiveData的监听中,对不同的异常进行了Toast的弹出提醒,如果每次进入一个页面,虽然请求成功了,但是因为errorLiveData还是能接收到通知,就会弹出一个Toast提醒框。现象如下:

dem.gif

那我们针对MutableLiveData将其修改为单事件响应的liveData,只有一个接收者能接收到信息,可以避免不必要的业务的场景中的事件消费通知。

class SingleLiveData : MutableLiveData() {

private val mPending = AtomicBoolean(false)

@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer) {

if (hasActiveObservers()) {
Log.w(TAG, “多个观察者存在的时候,只会有一个被通知到数据更新”)
}

super.observe(owner, Observer { t ->
if (mPending.compareAndSet(true, false)) {
observer.onChanged(t)
}
})

}

override fun setValue(value: T?) {
mPending.set(true)
super.setValue(value)
}

@MainThread
fun call() {
value = null
}

companion object {
private const val TAG = “SingleLiveData”
}
}
将BaseViewModel中的MutableLiveData替换为SingleLiveData就可以了。
最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

最后

分享一份工作1到5年以上的Android程序员架构进阶学习路线体系,希望能对那些还在从事Android开发却还不知道如何去提升自己的,还处于迷茫的朋友!

  • 阿里P7级Android架构师技术脑图;查漏补缺,体系化深入学习提升

  • **全套体系化高级架构视频;**七大主流技术模块,视频+源码+笔记

有任何问题,欢迎广大网友一起来交流

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
24)]

  • **全套体系化高级架构视频;**七大主流技术模块,视频+源码+笔记

[外链图片转存中…(img-TvjkTZBC-1712790160324)]

有任何问题,欢迎广大网友一起来交流

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-xVCFkkf3-1712790160325)]

  • 12
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值