告別ANR!Android中六種安全更新UI的方式
想象你在另一個城市(子線程)買了禮物,想送給女朋友(UI線程)。直接扔過去會砸傷人(崩潰),必須通過快遞站(主線程通信機(jī)制)。以下是安全送禮指南:
方案1:官方快遞站-runOnUiThread
適用場景:在Activity/Fragment中快速傳遞
// 子線程工作
new Thread(() -> {
String message = fetchMsgFromServer();
// 官方指定快遞點(diǎn)
runOnUiThread(() -> {
textView.setText(message); // 安全送達(dá)
});
}).start();
優(yōu)勢:
- ? 系統(tǒng)自帶,隨用隨取
- ? 自動識別當(dāng)前Activity生命周期
方案2:任意代收點(diǎn)-View.post
適用場景:在任何能拿到View的地方
// 在任意View可達(dá)的地方
fun updateProgress(progress: Int) {
Thread {
val current = calculateProgress()
// 隨便找個View當(dāng)快遞柜
progressBar.post {
progressBar.progress = current
}
}.start()
}
隱藏技巧:
? 即使View
還沒顯示也能寄存消息
? 支持延遲投遞:view.postDelayed({...}, 1000)
方案3:老牌物流-Handler
適用場景:需要精準(zhǔn)控制消息隊(duì)列
// 創(chuàng)建主線程Handler
Handler mainHandler=new Handler(Looper.getMainLooper());
void showNotification(String message) {
executorService.execute(() -> {
prepareNotification(message);
// 精準(zhǔn)派送
mainHandler.post(() -> {
notificationView.display(message);
});
});
}
避坑指南:
? 記得在onDestroy
時(shí)調(diào)用mHandler.removeCallbacksAndMessages(null)
? 用postDelayed
實(shí)現(xiàn)定時(shí)刷新:mHandler.postDelayed(updateTask, 5000)
方案4:智能管家-LiveData
適用場景:MVVM架構(gòu)下的數(shù)據(jù)驅(qū)動UI
// ViewModel中
private val _newsLiveData = MutableLiveData<List<News>>()
val newsLiveData: LiveData<List<News>> = _newsLiveData
fun loadNews() {
viewModelScope.launch(Dispatchers.IO) {
val news = repository.fetchNews()
_newsLiveData.postValue(news) // 自動切到主線程
}
}
// Activity中
newsViewModel.newsLiveData.observe(this) { news ->
adapter.submitList(news) // 安全更新RecyclerView
}
優(yōu)勢對比:
傳統(tǒng)方式 | LiveData |
需手動處理生命周期 | 自動解除訂閱 |
可能內(nèi)存泄漏 | 生命周期感知 |
多界面同步困難 | 數(shù)據(jù)共享方便 |
方案5:閃電俠-協(xié)程
適用場景:Kotlin項(xiàng)目中的異步處理
fun loadComments() {
lifecycleScope.launch {
val comments = withContext(Dispatchers.IO) {
api.getComments(postId)
}
// 自動切回主線程
binding.commentList.adapter = CommentAdapter(comments)
}
}
性能對比:
? 傳統(tǒng)線程:每次new Thread約消耗1MB內(nèi)存
? 協(xié)程:輕量級,1KB級內(nèi)存消耗
方案6:萬能工-RxJava
適用場景:復(fù)雜異步流處理
Observable.fromCallable(() -> db.queryUnreadMsg())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(messages -> {
badgeView.updateCount(messages.size);
});
高階用法:
// 合并多個數(shù)據(jù)源
Observable.merge(networkData, localData)
.filter(msg -> !msg.isDeleted)
.debounce(300, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateUI);
好的線程管理就像優(yōu)秀的交通管制,讓數(shù)據(jù)在正確的時(shí)間走正確的車道!現(xiàn)在就去優(yōu)化你的代碼吧~ ??