中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

湖南省建設(shè)廳網(wǎng)站首頁網(wǎng)絡(luò)顧問

湖南省建設(shè)廳網(wǎng)站首頁,網(wǎng)絡(luò)顧問,做網(wǎng)頁的軟件哪個好,網(wǎng)站的導(dǎo)入流量怎么做前言 關(guān)于IdleHandler,比較多同學(xué)錯誤地認為,這個Handler的作用是主線程空閑狀態(tài)時才執(zhí)行它,那么用它做一些耗時操作也沒所謂??墒荌dleHandler在主線程的MessageQueue中,執(zhí)行queueIdle()默認當(dāng)然也是執(zhí)行在主線程中的&#xff0…

前言

關(guān)于IdleHandler,比較多同學(xué)錯誤地認為,這個Handler的作用是主線程空閑狀態(tài)時才執(zhí)行它,那么用它做一些耗時操作也沒所謂??墒荌dleHandler在主線程的MessageQueue中,執(zhí)行queueIdle()默認當(dāng)然也是執(zhí)行在主線程中的,這里的耗時操作其實很容易引起卡頓和ANR。

IdleHandler的介紹

IdleHandler是一種在只有當(dāng)消息隊列沒有消息時或者是隊列中的消息還沒有到執(zhí)行時間時才會執(zhí)行的IdleHandler。從源碼上看,IdleHandler是一個回調(diào)接口,當(dāng)線程中的消息隊列將要阻塞等待消息的時候,就會回調(diào)該接口,也就是說消息隊列中的消息都處理完畢了,沒有新的消息了,處于空閑狀態(tài)時就會回調(diào)該接口。

public static interface IdleHandler {boolean queueIdle();
}

IdleHandler的使用

IdleHandler是MessageQueue的靜態(tài)內(nèi)部接口,通過靜態(tài)方法就能拿得到,不過要注意的事,當(dāng)前Looper是主線程的Looper的話,取到的也是主線程的MessageQueue

Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {@Overridepublic boolean queueIdle() {//空閑時處理邏輯return false;}
});

IdleHandler的問題

IdleHandler如果是主線程的執(zhí)行超過5s同樣也是會報ANR,我們通過主線程模擬休眠,會發(fā)現(xiàn)App直接ANR

Looper.myQueue().addIdleHandler(object : MessageQueue.IdleHandler {override fun queueIdle(): Boolean {Log.e("TAG", "[queueIdle] sleep(5000) start")Thread.sleep(5000)Log.e("TAG", "[queueIdle] sleep(5000) end")return false}
})

IdleHandler的監(jiān)控分析

為了防止IdleHandler濫用,監(jiān)控起來也是很有必要,特別是第三方產(chǎn)商經(jīng)常通過這個接口做一些耗時操作。通過查看源碼,找到IdleHandler的Hook點

  1. 通過Looper.myQueue().addIdleHandler()開始,可以看到是每次通過mIdleHandlers加入到隊列中
public void addIdleHandler(@NonNull IdleHandler handler) {if (handler == null) {throw new NullPointerException("Can't add a null IdleHandler");}synchronized (this) {mIdleHandlers.add(handler);}
}
  1. mIdleHandlers是一個列表,會保存每一個添加進來的IdleHandler
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
  1. Message#next()中,執(zhí)行完Handler消息空閑后,會將當(dāng)前的IdleHandler列表循環(huán)遍歷執(zhí)行queueIdle()
Message next() {.....for (;;) {.....if (mPendingIdleHandlers == null) {mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];}// 1、取出所有IdleHandlermPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);for (int i = 0; i < pendingIdleHandlerCount; i++) {final IdleHandler idler = mPendingIdleHandlers[i];mPendingIdleHandlers[i] = null; // release the reference to the handlerboolean keep = false;try {// 2、執(zhí)行IdleHandler的queueIdle()keep = idler.queueIdle();} catch (Throwable t) {Log.wtf(TAG, "IdleHandler threw exception", t);}if (!keep) {synchronized (this) {mIdleHandlers.remove(idler);}}}}
}

IdleHandler的監(jiān)控實現(xiàn)

  1. IdleHandler的執(zhí)行流程可以看出,Hook點就在mIdleHandlers列表中,將當(dāng)前的MessageQueue中的mIdleHandlers列表替換成自己的列表
class IdleHandlerMonitor {private HandlerThread idleHandlerThread;private Handler idleHandlerHandler;private static String mIdleHandler = null;IdleHandlerMonitor() {// 1、創(chuàng)建子線程的handler(idleHandlerHandler),方便后續(xù)在子線程發(fā)送消息不被主線程卡住影響if (Build.VERSION.SDK_INT >= 23) {this.idleHandlerThread = new HandlerThread("IdleHandlerThread");this.idleHandlerThread.start();this.idleHandlerHandler = new Handler(this.idleHandlerThread.getLooper());this.detectIdleHandler();}}@RequiresApi(api = 23)private void detectIdleHandler() {// 2、修改MessageQueue中的mIdleHandlers變量,傳入自定義的Listtry {MessageQueue mainQueue = Looper.getMainLooper().getQueue();Field field = MessageQueue.class.getDeclaredField("mIdleHandlers");field.setAccessible(true);CustomArrayList<MessageQueue.IdleHandler> myIdleHandlerArrayList = new CustomArrayList();field.set(mainQueue, myIdleHandlerArrayList);} catch (Throwable var4) {var4.printStackTrace();}}private class CustomArrayList<T> extends ArrayList {public boolean add(Object o) {if (o instanceof MessageQueue.IdleHandler) {// 3、將原來的IdleHandler包裝進自己的CustomIdleHandlerCustomIdleHandler customIdleHandler = new CustomIdleHandler((MessageQueue.IdleHandler) o);return super.add(customIdleHandler);}return super.add(o);}public boolean remove(@Nullable Object o) {if (o instanceof CustomIdleHandler) {return super.remove(((CustomIdleHandler) o));}return super.remove(o);}}private class CustomIdleHandler implements MessageQueue.IdleHandler {private MessageQueue.IdleHandler idleHandler;CustomIdleHandler(MessageQueue.IdleHandler idleHandler) {this.idleHandler = idleHandler;}@Overridepublic boolean queueIdle() {mIdleHandler = this.idleHandler.toString();idleHandlerHandler.removeCallbacks(idleHanlderRunnable);idleHandlerHandler.postDelayed(idleHanlderRunnable, 3000L);// 4、將包裝起來的IdleHandler取出來,執(zhí)行queueIdle,包裝前設(shè)置多一項3s的延時任務(wù)。// 只要queueIdle在3s內(nèi)沒執(zhí)行完,將執(zhí)行當(dāng)前的idleHanlderRunnableboolean ret = this.idleHandler.queueIdle();idleHandlerHandler.removeCallbacks(idleHanlderRunnable);return ret;}}// 5、報告輸出當(dāng)前Idle信息超時通知private static Runnable idleHanlderRunnable = () -> {Log.e("TAG", "[queueIdle] more then 3000L \n message=" + mIdleHandler);};
}

hook的巧妙點在于將當(dāng)前的List換成自己的List,然后在List的添加和刪除中,偷梁換柱成自己的IdleHandler進行加工處理

IdleHandler的驗證

Hook解決完之后,我們來通過Demo驗證下是否是我們想要的監(jiān)控,通過初始化IdleHandlerMonitor()啟動監(jiān)控,然后模擬3次IdleHandler發(fā)送不同時間的消息,最后看日志輸出,是否被捕獲到超時的Idle任務(wù)

private fun initIdelHandler() {IdleHandlerMonitor()Looper.myQueue().addIdleHandler(object : MessageQueue.IdleHandler {override fun queueIdle(): Boolean {Log.e("TAG", "[queueIdle] sleep(2000) start")Thread.sleep(2000)Log.e("TAG", "[queueIdle] sleep(2000) end")return false}})Looper.myQueue().addIdleHandler(object : MessageQueue.IdleHandler {override fun queueIdle(): Boolean {Log.e("TAG", "[queueIdle] sleep(5000) start")Thread.sleep(5000)Log.e("TAG", "[queueIdle] sleep(5000) end")return false}})Looper.myQueue().addIdleHandler(object : MessageQueue.IdleHandler {override fun queueIdle(): Boolean {Log.e("TAG", "[queueIdle] sleep(10000) start")Thread.sleep(10000)Log.e("TAG", "[queueIdle] sleep(10000) end")return false}})
}

通過日志輸出結(jié)果,可以看到當(dāng)前的Idle阻塞3s時候的代碼類位置

E/TAG: [queueIdle] sleep(2000) start
E/TAG: [queueIdle] sleep(2000) end
E/TAG: [queueIdle] sleep(5000) start
E/TAG: [queueIdle] more then 3000L message=com.example.syncbarriermonitor.MainActivity$initIdelHandler$2@4d9ab66
E/TAG: [queueIdle] sleep(5000) end
E/TAG: [queueIdle] sleep(10000) start
E/TAG: [queueIdle] more then 3000L message=com.example.syncbarriermonitor.MainActivity$initIdelHandler$3@be7cc0
http://www.risenshineclean.com/news/7395.html

相關(guān)文章:

  • 幫企業(yè)外賣網(wǎng)站做推移動網(wǎng)站優(yōu)化排名
  • 網(wǎng)站免費優(yōu)化工具怎樣宣傳網(wǎng)站
  • 在建設(shè)政府門戶網(wǎng)站時要充分考慮到引流推廣是什么意思
  • 廈門網(wǎng)紅鄭州seo技術(shù)
  • 網(wǎng)站建設(shè) 網(wǎng)站優(yōu)化5118數(shù)據(jù)分析平臺官網(wǎng)
  • 免費域名申請哪個網(wǎng)站好產(chǎn)品推廣方案ppt
  • 建站優(yōu)化收費石家莊抖音seo
  • 好看又免費的圖片素材網(wǎng)站成都網(wǎng)站推廣經(jīng)理
  • 電腦維修 做網(wǎng)站軟文網(wǎng)站名稱
  • 企業(yè)做網(wǎng)站需要什么資料關(guān)鍵詞優(yōu)化哪個好
  • 棗莊住房和城鄉(xiāng)建設(shè)局網(wǎng)站滄州網(wǎng)站優(yōu)化公司
  • 中山做網(wǎng)站博客推廣的方法與技巧
  • 深圳 公司網(wǎng)站建設(shè)優(yōu)化關(guān)鍵詞排名哪家好
  • 做網(wǎng)站一般什么配置超級外鏈自動發(fā)布工具
  • 品牌做網(wǎng)站搜索百度網(wǎng)址網(wǎng)頁
  • 申請做網(wǎng)站 論壇版主seo站長綜合查詢
  • 招財貓網(wǎng)站怎么做搜索熱詞排名
  • 做網(wǎng)站程序員都要先做維護么數(shù)字營銷是干啥的
  • 如何搭建免費網(wǎng)站營銷培訓(xùn)視頻課程免費
  • 建設(shè)網(wǎng)站要注意事項中國最大網(wǎng)站排名
  • 互聯(lián)網(wǎng)門戶網(wǎng)站是什么培訓(xùn)課程總結(jié)
  • 國外做網(wǎng)站公司能賺錢嗎知乎軟文推廣
  • wordpress程序代碼漯河seo推廣
  • 長安公司網(wǎng)站建設(shè)百度自媒體注冊入口
  • 肇慶網(wǎng)站建設(shè)方案外包惠州網(wǎng)站排名提升
  • 網(wǎng)站建設(shè)用什么軟件比較好優(yōu)化視頻
  • 微信如何做微商城網(wǎng)站微信視頻號小店
  • 莆田交友網(wǎng)站市場app推廣引流方法
  • 常州做網(wǎng)站怎么做個網(wǎng)站
  • 做cad室內(nèi)平面圖的家具素材網(wǎng)站網(wǎng)絡(luò)公司關(guān)鍵詞排名