Flutter technology is fat! Advanced learning for Android senior engineers—Android hot fix principles, detailed Android learning guide

Android global exception handling

When doing android project development, everyone knows that if the program makes a mistake, a forced exit pop-up box will pop up. This is no problem in itself, but this UI is really ugly, not to mention users can’t accept it, even ourselves. It may not be acceptable. Although we always go through careful testing when we release the program, we will inevitably encounter unexpected errors.

Today, I will customize the handling of a program error, similar to the crash of iphone. (Although the flashback is not what users want to see, it is obviously much better than the native pop-up in terms of user experience)

1. Overview of MVVM architecture pattern

This is a small DEMO that uses the MVVM architecture model + Kotlin coroutine + JetPack (ViewModel + LiveData) + Retrofit to implement the WanAndroid login interface. The WanAndroid client will be gradually improved in the future.

1、ViewModel

In order to separate the view data ownership from the interface controller Activity/Fragment logic, the architecture component provides the ViewModel auxiliary program class for the interface controller, which is responsible for preparing data for the interface. ViewModel objects are automatically retained during configuration changes so that the data they store is immediately available for use by the next Activity or Fragment instance.

2、LiveData

LiveData is an observable data storage class with life cycle awareness, which means that it follows the life cycle of other application components such as Activity, Fragment, or Service, ensuring that LiveData only updates application component observers in the active life cycle state. LiveData objects are usually stored in ViewModel objects and can be accessed through getter methods.

3. Kotlin coroutine

The coroutine is attached to the thread, which can realize the sequential writing of asynchronous code and automatic thread switching. And ViewModelScope defines ViewModelScope for each ViewModel in the application. If the ViewModel is cleared, the coroutines started in this range will be automatically cancelled.

4、Retrofit

Declare the network request function in the service interface as a suspend interface function to support Kotlin threads, and transmit the result of the suspend function as a LiveData object.

2、ViewModel

//获取ViewModel
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)` 

The time range of the ViewModel object's existence is the Lifecycle passed to the ViewModelProvider when the ViewModel is obtained. The ViewModel will remain in memory until the Lifecycle that limits its existence time range is permanently gone: for Activity, it is when the Activity is completed; for Fragment, it is when the Fragment is separated.

3、LiveData

//对User数据进行观察
viewModel.user.observe(this, Observer {
    //展示登录结果
    if (it.errorCode == 0) {
        Toast.makeText(this, it.data?.nickname, Toast.LENGTH_SHORT).show()
    } else {
        Toast.makeText(this, it.errorMsg, Toast.LENGTH_SHORT).show()
    }
})

Using LiveData has the following advantages: Ensure that the interface conforms to the data state

LiveData 遵循观察者模式。当生命周期状态发生变化时,LiveData 会通知 Observer 对象。您可以整合代码以在这些 Observer 对象中更新界面。观察者可以在每次发生更改时更新界面,而不是在每次应用数据发生更改时更新界面。

No memory leaks

观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。

Will not cause a crash due to Activity stopping

如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。
不再需要手动处理生命周期
界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。

Data is always up to date

如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。

Appropriate configuration changes

如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。

share resources

可以使用单一实例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。

4. Kotlin coroutine

4.1, the essence of asynchronous

What is asynchronous?

异步就是同时进行一个以上彼此目的不同的任务。

But for tasks with front and back dependencies, how to deal with asynchronous?

利用异步中的回调机制处理。

Why do we need an asynchronous callback mechanism?

因为不同的任务之间存在前后的依赖关系。

What are the disadvantages of the asynchronous callback mechanism?

代码结构过分耦合,遇到多重函数回调的嵌套耦合,也就是回调地狱,代码会难以维护。

What is the solution to callback hell?

链式调用结构。
常见方式就是使用RxJava,它是反应函数式编程在Java中的实现。
但是RxJava中流的创建、转化与消费都需要使用到各种类和丰富的操作符,加大了RxJava的学习成本。
减少在无封装情况下使用RxJava,因为你无法保证团队里面的每一个成员都能看懂它,并且在修改时都能做出正确选择。

In serial execution, although the code is indeed executed sequentially, it is actually executed sequentially on different threads. So why in the serial execution, the code execution order is the same, but the callback is still used?

因为串行的执行中,执行是阻塞式的,主线程的阻塞会导致很严重的问题,所以所有的耗时操作不能在主线程中执行,所以就需要多线程并行来执行。

In parallel execution, asynchronous callbacks are actually multithreaded sequential execution of code. Can you not only write the code in a sequential manner, but also allow the code to be executed in different threads in order to automatically complete the thread switching work?

那就是Kotlin协程。
Kotlin 的协程是一种无栈协程的实现,它的控制流转依靠对协程体本身编译生成的状态机的状态流转来实现,变量保存也是通过闭包语法来实现的。

in conclusion:

异步回调就是代码的多线程顺序执行,而Kotlin协程可以实现顺序编写异步代码,自动进行线程切换。

So what is the principle of automatic thread switching by coroutine?

Yield:让出CPU,放弃调度控制权,回到上一次Resume的地方
Resume:获取调度控制权,继续执行程序,到上一次Yield的地方

example:

1. GlobalScope.launch发起了一个协程,并在IO线程上执行,
2\. 在协程里,去调用接口获取结果。
3. 拿到结果,使用withContext(Dispatchers.Main)切换到主线程并更新界面

4.2, the type of coroutine

是协程范围,指的是协程内的代码运行的时间周期范围,如果超出了指定的协程范围,协程会被取消执行。

GlobalScope

指的是与应用进程相同的协程范围,也就是在进程没有结束之前协程内的代码都可以运行。

The scope of lifecycle-aware coroutine provided in JetPack:

ViewModelScope,为应用中的每个 ViewModel 定义了 ViewModelScope。如果 ViewModel 已清除,则在此范围内启动的协程都会自动取消。

LifecycleScope,为每个 Lifecycle 对象定义了 LifecycleScope。在此范围内启动的协程会在 Lifecycle 被销毁时取消。

使用 LiveData 时,可能需要异步计算值。可以使用 liveData 构建器函数调用 suspend 函数,并将结果作为 LiveData 对象传送。

Related link: https://developer.android.google.cn/topic/libraries/architecture/coroutines

4.3, the start of the coroutine

launch method:

/**
 * 重要知识:ViewModel+协程
 */
fun ViewModel.launch(
    block: suspend CoroutineScope.() -> Unit,
    onError: (e: Throwable) -> Unit = {},
    onComplete: () -> Unit = {}
) {
    viewModelScope.launch(CoroutineExceptionHandler { _, e -> onError(e) }) {
        try {
            block.invoke(this)
        } finally {
            onComplete()
        }
    }
}

Source code:

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

4.3.1, launch method explanation

context

协程上下文,可以指定协程运行的线程。默认与指定的CoroutineScope中的coroutineContext保持一致,比如GlobalScope默认运行在一个后台工作线程内。也可以通过显示指定参数来更改协程运行的线程,Dispatchers提供了几个值可以指定:Dispatchers.Default、Dispatchers.Main、Dispatchers.IO、Dispatchers.Unconfined。

start

协程的启动模式。默认的CoroutineStart.DEFAULT是指协程立即执行,除此之外还有CoroutineStart.LAZY、CoroutineStart.ATOMIC、CoroutineStart.UNDISPATCHED。

block

协程主体。也就是要在协程内部运行的代码,可以通过lamda表达式的方式方便的编写协程内运行的代码。

CoroutineExceptionHandler

指定CoroutineExceptionHandler来处理协程内部的异常。

Job

返回值,对当前创建的协程的引用。可以通过Job的start、cancel、join等方法来控制协程的启动和取消。

4.4, suspend function

The suspend keyword only serves to mark that this function is a time-consuming operation and must be executed in the coroutine, while the withContext method performs thread switching.

The code in the coroutine automatically switches to other threads and then automatically switches back to the main thread! Sequential writing ensures logical intuitiveness, and the automatic thread switching of the coroutine ensures non-blocking code. The suspend function must be called in the coroutine or other suspend function, that is, the suspend function must be executed directly or indirectly in the coroutine.

Then why is the code in the coroutine not executed in the main thread? And why does it automatically switch back to the main thread after execution?

The suspension of the coroutine can be understood as the process in which the code in the coroutine leaves the thread where the coroutine is located, and the recovery of the coroutine can be understood as the process in which the code in the coroutine reenters the thread where the coroutine is located. The coroutine is to switch threads through this suspend recovery mechanism.

4.5、async await方法

Use the async method to wrap the suspend method to execute concurrent requests. After the concurrent results are returned, switch to the main thread, and then use the await method to obtain the concurrent request results.

5、Retrofit

HTTP interface suspend function:

interface ApiService {
    @FormUrlEncoded
    @POST("user/login")
    suspend fun loginForm(@Field("username")  username: String,@Field("password")  password: String): BaseResponse<User>
}

Kotlin generics:

data class BaseResponse<T>(
    val errorCode: Int=0,
    val errorMsg:String? = null,
    var data: T? = null
)

This is a small DEMO that uses the MVVM architecture model + Kotlin coroutine + JetPack (ViewModel + LiveData) + Retrofit to implement the WanAndroid login interface. The WanAndroid client will be gradually improved in the future.

New beginning

There are no shortcuts to change your life. You need to take this path yourself. Only deep thinking, continuous reflection and summary, maintaining the enthusiasm for learning, and building your own complete knowledge system step by step are the ultimate ways to win. It is also the mission that programmers should undertake.

If there is a need for advanced Android senior engineer system learning materials, I can share it with everyone for free, friends who need the full version, [ click here to see all the content ].

"Series of Learning Videos"

"Series of Learning Documents"

"My Interview Trip to a Big Factory"

%E5%8F%91%E4%B8%8D%E4%BC%9A%E8%BF%99%E4%BA%9B%EF%BC%9F%E5%A6%82%E4%BD%95%E9%9D%A2%E8%AF%95%E6%8B%BF%E9%AB%98%E8%96%AA%EF%BC%81.md)】。**

"Series of Learning Videos"
[External link pictures are being transferred...(img-MR2FQd0v-1611041967013)]

"Series of Learning Documents"

[External link image is being transferred...(img-dAiROcvg-1611041967015)]

"My Interview Trip to a Big Factory"

[External link pictures are being transferred...(img-K7K9Ft58-1611041967017)]

Guess you like

Origin blog.csdn.net/CHAMPION8888/article/details/112841366