1. hooks原理
2. Android 中 UI 的刷新机制
- 当界面需要刷新时(
View.invalidate()或requestLayout()被调用),最终会触发一次绘制请求。系统会在 下一帧的 VSync 信号到来时 执行 UI 渲染流程 - 当调用invalidate时,最终会执行
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 添加handler消息屏障,用于阻塞hannlde执行
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 向 Choreographer 注册一个帧回调mTraversalRunnable,等待下一帧 VSync 到来。当下一帧 VSync 到达后,会执行callback.doFrame(frameTimeNanos),触发mTraversalRunnable回调
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
在mTraversalRunnable中移除消息屏障,并依次执行performMeasure() → performLayout() → performDraw()
3.协程
自定义协程作用域
class CustomerScope : CoroutineScope, Closeable {
/** 让同一个作用域中的协程相互独立,一个失败不会影响其他协程 */
private val job = SupervisorJob()
/** 协程上下文 */
override val coroutineContext: CoroutineContext = Dispatchers.IO + job
/** 取消该scope中所有正在运行的协程 */
override fun close() {
job.cancel()
}
}
使用
val scope = CustomerScope()
scope.launch{
doSomething()
}
协程并发执行
runBlocking {
val start = System.currentTimeMillis()
val user = async { getUserFromNetwork() }
val posts = async { getPostsFromNetwork() }
// 同时发起两个异步任务
println("Result: ${user.await()} & ${posts.await()}")
println("Time = ${System.currentTimeMillis() - start}ms")
}
suspend fun getUserFromNetwork(): String {
delay(1000)
return "Tom"
}
suspend fun getPostsFromNetwork(): String {
delay(1000)
return "Post List"
}
接口合并请求
// viewModelScope 属于ViewModel的生命周期作用域;
// 它的Job是一个SupervisorJob;只作用于不同launch之间
// 所以即使内部某个子协程失败,也不会取消整个 ViewModel;
// 同一个 launch 内部的子协程,还是存在父子取消依赖关系的
viewModelScope.launch {
// 是一个suspend 函数,可以在协程体内创建一个新的监督作用域;
// 它会屏蔽子任务间的失败传播;
supervisorScope {
val tasks = listOf(
async { runCatching{api.getUserInfo()} },
async { runCatching{api.getUserPosts()} }
)
val (user, posts) = tasks.awaitAll()
}
}
协程错误处理:
- 使用CoroutineExceptionHandler
val handler = CoroutineExceptionHandler { _, e ->
Log.e("Coroutine", "未捕获异常: ${e.message}")
}
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main + handler)
scope.launch {
launch {
throw RuntimeException("子任务 A 失败")
}
launch {
delay(1000)
println("子任务 B 仍然正常执行 ✅")
}
}
输出
未捕获异常: 子任务 A 失败
子任务 B 仍然正常执行 ✅
2. 使用try catch 例如上方接口合并请求中runCatch
4. LiveData
在fragment onResume时liveData会再次通知更新,修复方案
class SingleLiveEvent<T> : MutableLiveData<T>() {
private val pending = AtomicBoolean(false)
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner) { t ->
if (pending.compareAndSet(true, false)) {
observer.onChanged(t)
}
}
}
override fun setValue(t: T?) {
pending.set(true)
super.setValue(t)
}
}
5.关于LayoutInflater,它是如何通过 inflate 方法获取到具体View
inflate(resource)
↓
getLayout(resource)
↓
XmlPullParser -> 解析XML
↓
createViewFromTag() -> 反射创建View实例
↓
rInflateChildren() -> 递归解析子View
↓
addView() -> 挂载到父容器
↓
返回根View
6.自定义View
canvas 绘制各种形状View
7.接口错误处理
override fun dataOrNull(): T? {
check(resp)
return resp.data
}
private fun check(resp: IResponse<T>) {
val errorCode = resp.errorCode
val errorMessage = resp.errorMessage
if (errorCode != 0) {
throw CustomerException(errorCode, errorMessage, resp)
}
}
ViewModelScope.launch {
val result = kotlin.runCatching {
apiServiceKt.useInfo().dataOrNull()
}
if (result.isSuccess) {
} else {
// 判断是否是自定义Exception,不是的话为系统抛出异常,例如JsonException
if (result.exceptionOrNull() is CustomerException) {
} else {
}
}
}
8. 多个接口同时返回token过期
使用自定义拦截器,在拦截器里面判断errCode
object LoginManager {
private var isShow = false
// 打开登录弹框
fun showLoginDialog() {
if(isShow) {
return
}
isShow = true
Dialog.show("token 过期", object: ClickListener{
override fun onDialogButtonClick() {
mShowDialog = false
// 跳转到登录页
}
})
}
}
class UerTokenInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val call = chain.call()
val request = chain.request()
val response = chain.proceed(request)
val responseJson = response.toJSONObject()
val errorCode = responseJson.get("errCode")
if(errCode == "400001") { // 弹出登录弹框
}
return response
}
}
9. okhttp 内部实现 10. recyclewView 内部实现
- handle 消息如何插入
- RN 不适合的场景
- 目前使用RN遇到的瓶颈 解决方案