国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > Android > 正文

Android開(kāi)發(fā)中Looper.prepare()和Looper.loop()

2019-12-12 04:41:35
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

什么時(shí)候需要 Looper

  Looper用于封裝了android線程中的消息循環(huán),默認(rèn)情況下一個(gè)線程是不存在消息循環(huán)(message loop)的,需要調(diào)用Looper.prepare()來(lái)給線程創(chuàng)建一個(gè)消息循環(huán),調(diào)用Looper.loop()來(lái)使消息循環(huán)起作用,使用Looper.prepare()和Looper.loop()創(chuàng)建了消息隊(duì)列就可以讓消息處理在該線程中完成。

使用Looper需要注意什么

  寫(xiě)在Looper.loop()之后的代碼不會(huì)被立即執(zhí)行,當(dāng)調(diào)用后mHandler.getLooper().quit()后,loop才會(huì)中止,其后的代碼才能得以運(yùn)行。Looper對(duì)象通過(guò)MessageQueue來(lái)存放消息和事件。一個(gè)線程只能有一個(gè)Looper,對(duì)應(yīng)一個(gè)MessageQueue。

比如下面的代碼,只要調(diào)用了getLooper().quit()后代碼2才會(huì)執(zhí)行。

class LooperThread extends Thread{4 public void run() {Looper.prepare();//代碼1....Looper.loop();//代碼2....} }

警惕線程未終止造成的內(nèi)存泄露;譬如在Activity中關(guān)聯(lián)了一個(gè)生命周期超過(guò)Activity的Thread,在退出Activity時(shí)切記結(jié)束線程。一個(gè)典型的例子就是HandlerThread的run方法是一個(gè)死循環(huán),它不會(huì)自己結(jié)束,線程的生命周期超過(guò)了Activity生命周期,我們必須手動(dòng)在Activity的銷(xiāo)毀方法中中調(diào)運(yùn)thread.getLooper().quit();才不會(huì)泄露。

Looper與Activity

Activity的MainUI線程默認(rèn)是有消息隊(duì)列的。所以在Activity中新建Handler時(shí),不需要先調(diào)用Looper.prepare()

主線程中的Looper.loop()一直無(wú)限循環(huán)為什么不會(huì)造成ANR

ActivityThread.java 是主線程入口的類(lèi),這里你可以看到寫(xiě)Java程序中司空見(jiàn)慣的main方法,而main方法正是整個(gè)Java程序的入口。

ActivityThread源碼

public static final void main(String[] args) {...//創(chuàng)建Looper和MessageQueueLooper.prepareMainLooper();...//輪詢(xún)器開(kāi)始輪詢(xún)Looper.loop();...}

Looper.loop()方法

while (true) {//取出消息隊(duì)列的消息,可能會(huì)阻塞Message msg = queue.next(); // might block...//解析消息,分發(fā)消息msg.target.dispatchMessage(msg);...}

ActivityThread的main方法主要就是做消息循環(huán),一旦退出消息循環(huán),那么你的應(yīng)用也就退出了。那為什么這個(gè)死循環(huán)不會(huì)造成ANR異常呢?

因?yàn)锳ndroid 的是由事件驅(qū)動(dòng)的,looper.loop() 不斷地接收事件、處理事件,每一個(gè)點(diǎn)擊觸摸或者說(shuō)Activity的生命周期都是運(yùn)行在 Looper.loop() 的控制之下,如果它停止了,應(yīng)用也就停止了。只能是某一個(gè)消息或者說(shuō)對(duì)消息的處理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它。也就說(shuō)我們的代碼其實(shí)就是在這個(gè)循環(huán)里面去執(zhí)行的,當(dāng)然不會(huì)阻塞了。

handleMessage方法部分源碼

public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {case LAUNCH_ACTIVITY: {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");final ActivityClientRecord r = (ActivityClientRecord) msg.obj;r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);handleLaunchActivity(r, null);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}break;case RELAUNCH_ACTIVITY: {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");ActivityClientRecord r = (ActivityClientRecord) msg.obj;handleRelaunchActivity(r);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}break;case PAUSE_ACTIVITY:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");handlePauseActivity((IBinder) msg.obj, false, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 2) != 0);maybeSnapshot();Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;case PAUSE_ACTIVITY_FINISHING:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");handlePauseActivity((IBinder) msg.obj, true, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 1) != 0);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;...........}}

可以看見(jiàn)Activity的生命周期都是依靠主線程的Looper.loop,當(dāng)收到不同Message時(shí)則采用相應(yīng)措施。

如果某個(gè)消息處理時(shí)間過(guò)長(zhǎng),比如你在onCreate(),onResume()里面處理耗時(shí)操作,那么下一次的消息比如用戶(hù)的點(diǎn)擊事件不能處理了,整個(gè)循環(huán)就會(huì)產(chǎn)生卡頓,時(shí)間一長(zhǎng)就成了ANR。

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 河源市| 合水县| 老河口市| 葫芦岛市| 建始县| 白水县| 濉溪县| 上栗县| 安平县| 扎兰屯市| 太谷县| 武山县| 旬邑县| 葫芦岛市| 蓬莱市| 房产| 彭阳县| 普兰店市| 普陀区| 鹤山市| 柘荣县| 新安县| 安西县| 邵阳市| 宁乡县| 定陶县| 临颍县| 二连浩特市| 祁连县| 五华县| 和静县| 尤溪县| 綦江县| 成安县| 三亚市| 沅江市| 灌南县| 石嘴山市| 朝阳市| 郴州市| 曲水县|