The principle turned out to be this! 2021 ByteDance+JD+Meituan interview summary! Write to Android developers who are looking for a job

After Jinjiuyin 10, all major online platforms will share various experiences, including those who have received offers or failed interviews. I believe most people have got their favorite offers from major companies, but are there a few who have not been able to get into them? I am annoyed by the big factory I long for, so how can I enter the big factory? What should I prepare to enter the big factory?

At this time, the director of Byte has something to say, regarding the ByteDance of the interview, the boss summarized some interview points. I believe that it can also bring a lot of help in other interviews. Today I have sorted it out, and I hope it can help more. Many friends.

1. Overview of MVVM architecture pattern

This is the use of the MVVM architecture model + Kotlin coroutine + JetPack (ViewModel + LiveData) + Retrofit architecture to implement a small DEMO of the WanAndroid login interface, and the WanAndroid client will be gradually improved in the follow-up

1、ViewModel

In order to separate the ownership of view data from the activity/fragment logic of the interface controller, 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 the 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 has been 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: to ensure that the interface conforms to the data state

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

No memory leaks

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

Will not cause a crash when the Activity is stopped

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

Data is always up-to-date

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

Appropriate configuration changes

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

Share resource

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

4. Kotlin coroutine

4.1, the essence of asynchrony

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 are the solutions 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 range of lifecycle-aware coroutines 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 the non-blocking nature of the 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 the use of the MVVM architecture model + Kotlin coroutine + JetPack (ViewModel + LiveData) + Retrofit architecture to implement a small DEMO of the WanAndroid login interface, and the WanAndroid client will be gradually improved in the follow-up

Write at the end

In the technical field, there is no single course that you can do once and for all after you finish it. The best course can only be "the master leads the door, and the practice depends on the individual." The phrase "learning endlessly" is not only a good habit in any technical field, but also a necessary prerequisite for programmers and engineers not to be eliminated by the times and to obtain better opportunities and development.

If you feel that your learning efficiency is low and you lack correct guidance, you can join a technical circle with rich resources and a strong learning atmosphere to learn and communicate together !

Join us! There are many front-line technical experts in the group, as well as code farmers who are struggling in small factories or outsourcing companies. We are committed to creating an equal, high-quality Android communication circle. It may not be possible to make everyone's technology advance by leaps and bounds in the short term. In the long run, vision, pattern, and long-term development direction are the most important.

The 35-year-old middle-aged crisis is mostly caused by being led by short-term interests and squeezing out the value prematurely. If you can establish a correct long-term career plan from the beginning. After 35, you will only be more valuable than those around you.

%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)!**

Join us! There are many front-line technical experts in the group, as well as code farmers who are struggling in small factories or outsourcing companies. We are committed to creating an equal, high-quality Android communication circle. It may not be possible to make everyone's technology advance by leaps and bounds in the short term. In the long run, vision, pattern, and long-term development direction are the most important.

The 35-year-old middle-aged crisis is mostly caused by being led by short-term interests and squeezing out the value prematurely. If you can establish a correct long-term career plan from the beginning. After 35, you will only be more valuable than those around you.

Guess you like

Origin blog.csdn.net/a120464/article/details/113930855