多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > [置頂] [Android] 任意時刻從子線程切換到主線程的實現

[置頂] [Android] 任意時刻從子線程切換到主線程的實現

來源:程序員人生   發布時間:2014-12-15 08:58:07 閱讀次數:3392次

========================================================
作者:qiujuer
博客:blog.csdn.net/qiujuer
網站:www.qiujuer.net
開源庫:Genius-Android
轉載請注明出處:http://blog.csdn.net/qiujuer/article/details/41599383
========================================================

引入

在Android開發中常常會遇到網絡要求數據庫數據準備等1些耗時的操作;而這些操作是不允許在主線程中進行的。由于這樣會梗塞主線程致使程序出現未響應情況。

所以只能另起1個子線程進行這些耗時的操作,完成后再顯示到界面。盡人皆知,界面等控件操作只能在主線程中完成;所以不可避免的需要從子線程切換到主線程

方法

對這樣的情況在Android 中比較常見的是使用AsynTask類或 Handler來進行線程切換;而其中AsynTask是官方封裝的類,較為簡單,效力也比較可以,但是其實不合適所有的情況,最少我使用了1兩次后就再也沒有使用了。使用 Handler可以說是最萬能的方式,其原理是消息循環,在主線程中建立Handler 變量時,就會啟動Handler消息循環,1個個的處理消息隊列中的任務。但是其也有辣手的時候;其辣手的地方就是麻煩。

每次都需要去建立1個 Handler 類,然后使用voidhandleMessage(Messagemsg) 方法把消息取出來進行界面操作,而其中還要遇到參數的傳遞等問題,說起來真的是挺麻煩的。

想法

既然有著這么多的問題,但是又有其的優勢,我們何不自行封裝1次呢?

這里我梳理1下思路:

  1. 還是使用 Handler進行線程切換
  2. 在子線程中能通過簡單的調用就切換到主線程進行工作
  3. 在子線程切換到主線程時,子線程進入阻塞直到主線程履行完成(知道為何有這樣的需求么?)
  4. 1定要保證其效力
  5. 主線程的履行要有時間限制,不能履行太長時間致使主線程阻塞

我能想到的就是這些;觀眾老爺們咋樣?可否還有需求?

說干就干,梳理1下實現方法

  • 使用Handler 實現,既然這樣那末主方法固然就是采取繼承Handler 來實現
  • 而要簡單同時又要能隨時進入方法 那末對外采取靜態方法是個不錯的選擇
  • 而要保證效力的話,那就不能讓Handler 的消息隊列過于太多,但是又要滿足能隨時調用,那末采取外部 Queue
  • 更具情況有阻塞與不阻塞子線程兩種情況,那末采取兩個 Queue吧,分開來好1點
  • 要保證不能長時間在主線程履行那末對隊列的履行1定要有時間限制加1個時間變量吧
  • 固然最后斟酌了1下,既然要簡單那末傳入參數采取Runnable 是很爽的

萬事俱備,只欠東風了;好了進入下1環節。

CodeTime

首先我們建立1個ToolKit類:
public class ToolKit { /** * Asynchronously * * @param runnable Runnable Interface */ public static void runOnMainThreadAsync(Runnable runnable) { } /** * Synchronously * * @param runnable Runnable Interface */ public static void runOnMainThreadSync(Runnable runnable) { } }

兩個對外的方法簡單來講就是這樣了;但是其功能實現就需要使用繼承Handler了。

建立類HandlerPoster,繼承自Handler:

final class HandlerPoster extends Handler { private final int ASYNC = 0x1; private final int SYNC = 0x2; private final Queue<Runnable> asyncPool; private final Queue<SyncPost> syncPool; private final int maxMillisInsideHandleMessage; private boolean asyncActive; private boolean syncActive; HandlerPoster(Looper looper, int maxMillisInsideHandleMessage) { super(looper); this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage; asyncPool = new LinkedList<>(); syncPool = new LinkedList<>(); } void dispose() { this.removeCallbacksAndMessages(null); this.asyncPool.clear(); this.syncPool.clear(); } void async(Runnable runnable) { synchronized (asyncPool) { asyncPool.offer(runnable); if (!asyncActive) { asyncActive = true; if (!sendMessage(obtainMessage(ASYNC))) { throw new GeniusException("Could not send handler message"); } } } } void sync(SyncPost post) { synchronized (syncPool) { syncPool.offer(post); if (!syncActive) { syncActive = true; if (!sendMessage(obtainMessage(SYNC))) { throw new GeniusException("Could not send handler message"); } } } } @Override public void handleMessage(Message msg) { if (msg.what == ASYNC) { boolean rescheduled = false; try { long started = SystemClock.uptimeMillis(); while (true) { Runnable runnable = asyncPool.poll(); if (runnable == null) { synchronized (asyncPool) { // Check again, this time in synchronized runnable = asyncPool.poll(); if (runnable == null) { asyncActive = false; return; } } } runnable.run(); long timeInMethod = SystemClock.uptimeMillis() - started; if (timeInMethod >= maxMillisInsideHandleMessage) { if (!sendMessage(obtainMessage(ASYNC))) { throw new GeniusException("Could not send handler message"); } rescheduled = true; return; } } } finally { asyncActive = rescheduled; } } else if (msg.what == SYNC) { boolean rescheduled = false; try { long started = SystemClock.uptimeMillis(); while (true) { SyncPost post = syncPool.poll(); if (post == null) { synchronized (syncPool) { // Check again, this time in synchronized post = syncPool.poll(); if (post == null) { syncActive = false; return; } } } post.run(); long timeInMethod = SystemClock.uptimeMillis() - started; if (timeInMethod >= maxMillisInsideHandleMessage) { if (!sendMessage(obtainMessage(SYNC))) { throw new GeniusException("Could not send handler message"); } rescheduled = true; return; } } } finally { syncActive = rescheduled; } } else super.handleMessage(msg); } }

下面來講說這個我花了很大時間弄出來的類。

類的變量部份:

兩個標識,兩個隊列,兩個履行狀態,1個時間限制;很好理解吧?標識為了區分分別是處理那個隊列使用;隊列固然是裝著任務了;履行狀態是為了不重復發送消息致使消息隊列過量;時間限制這個最好理解了。

下面來講說方法部份:

構造函數HandlerPoster(Looper_looper,int_maxMillisInsideHandleMessage)

傳入兩個參數,分別是 Looper,用于初始化到主線程,后面的是時間限制;然后初始化了兩個隊列。

燒毀函數void_dispose()首先去除掉沒有處理的消息,然后清空隊列。

添加異步履行方法void_async(Runnable_runnable):

void async(Runnable runnable) { synchronized (asyncPool) { asyncPool.offer(runnable); if (!asyncActive) { asyncActive = true; if (!sendMessage(obtainMessage(ASYNC))) { throw new GeniusException("Could not send handler message"); } } } }

可以看見進入方法后第1件事兒就是進入同步狀態,然后調用asyncPool.offer(runnable);把任務寫入到隊列。

以后判斷當前是不是處于異步任務履行中,如果不是:立刻改變狀態,然后發送1個消息給當前Handler,固然不要忘記了傳入標識。

固然為了效力其消息的構造也是通過obtainMessage(ASYNC)方法來完成,為的就是不過量建立新的Message,盡可能使用當前隊列中空閑的消息。

添加同步履行方法void_sync(SyncPost_post)

void sync(SyncPost post) { synchronized (syncPool) { syncPool.offer(post); if (!syncActive) { syncActive = true; if (!sendMessage(obtainMessage(SYNC))) { throw new GeniusException("Could not send handler message"); } } } }

可以看到,這里傳入的其實不是Runnable 而是SyncPost這是為了同步而對Runnable進行了1次封裝后的類;后面介紹。

一樣是進入同步,添加,判斷,發送消息。

任務履行者@Override_void_handleMessage(Message_msg):

這里是復寫的Handler的消息處理方法,鐺鐺前Handler消息隊列中有消息的時候將會依照順序1個個的調用該方法。

分段來看:

if (msg.what == ASYNC) { boolean rescheduled = false; try { long started = SystemClock.uptimeMillis(); while (true) { Runnable runnable = asyncPool.poll(); if (runnable == null) { synchronized (asyncPool) { // Check again, this time in synchronized runnable = asyncPool.poll(); if (runnable == null) { asyncActive = false; return; } } } runnable.run(); long timeInMethod = SystemClock.uptimeMillis() - started; if (timeInMethod >= maxMillisInsideHandleMessage) { if (!sendMessage(obtainMessage(ASYNC))) { throw new GeniusException("Could not send handler message"); } rescheduled = true; return; } } } finally { asyncActive = rescheduled; } }

進入后首先判斷是不是是進行異步處理的消息,如果是那末進入該位置。

進入后我們進行了try_finally有1個變量long_started用于標識開始時間。

當履行1個任務后就判斷1次如果超過了每次占用主線程的時間限制,那末不管隊列中的任務是不是履行完成都退出,同時發起1個新的消息到Handler循環隊列。

while部份,我們從隊列取出1個任務,采取Poll方法;判斷是不是為空,如果為空進入隊列同步塊;然后再取1次,再次判斷。

如果恰巧在進入同步隊列之前有新的任務來了,那末第2次取到確當然就不是 NULL也就會繼續履行下去。反之,如果還是為空;那末重置當前隊列的狀態為false同時跳出循環。

下面來看第2部份:
else if (msg.what == SYNC) { boolean rescheduled = false; try { long started = SystemClock.uptimeMillis(); while (true) { SyncPost post = syncPool.poll(); if (post == null) { synchronized (syncPool) { // Check again, this time in synchronized post = syncPool.poll(); if (post == null) { syncActive = false; return; } } } post.run(); long timeInMethod = SystemClock.uptimeMillis() - started; if (timeInMethod >= maxMillisInsideHandleMessage) { if (!sendMessage(obtainMessage(SYNC))) { throw new GeniusException("Could not send handler message"); } rescheduled = true; return; } } } finally { syncActive = rescheduled; } } else super.handleMessage(msg);

首先還是判斷,如果是同步任務消息就進入,如果還是否是 那末只有調用super.handleMessage(msg);了。

從上面的處理部份可以看出來其處理的進程與第1部份可以說是完全1樣的。

只不過是從不同隊列取出不同的類SyncPost,然后判斷履行,和發送不同標識的消息;可以說如果懂了第1部份,這部份是毫無營養的。

這里就有問題了,既然方法操作流程1樣,那末同步與異步是在哪里進行辨別的?

這里就要看看SyncPost了:
final class SyncPost { boolean end = false; Runnable runnable; SyncPost(Runnable runnable) { this.runnable = runnable; } public void run() { synchronized (this) { runnable.run(); end = true; try { this.notifyAll(); } catch (Exception e) { e.printStackTrace(); } } } public void waitRun() { if (!end) { synchronized (this) { if (!end) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }

首先看看SyncPost的構造函數:

是否是傳入1個Runnable接口?所以說是對Runnable 的簡單封裝。

可以看見其public_void_run()方法:

在該方法中我們進入了同步塊,然后調用Runnable接口的run方法。同時在履行完成后將其中的1個狀態變量進行了改變boolean_end=true;

然后調用this.notifyAll();通知等待的部份可以繼續了,固然有這樣的情況;假設在進入該同步塊的時候子線程還未履行到this.wait();部份呢?所以我們為此準備了endtry。

然后看看public_void_waitRun()方法:

在這個中,我們首先判斷狀態,如果狀態已變了,那末證明子線程履行到此處時,主線程和履行了void_run()。

所以也就不用進入同步塊進行等待了,不然那還不等死???反之就進入進行等待直到主線程調用this.notifyAll();


豪情部份

馬上進入到完成部份了,組建都完善了那末該進行最后的組裝了。

回到類classToolKit

public class ToolKit { private static HandlerPoster mainPoster = null; private static HandlerPoster getMainPoster() { if (mainPoster == null) { synchronized (ToolKit.class) { if (mainPoster == null) { mainPoster = new HandlerPoster(Looper.getMainLooper(), 20); } } } return mainPoster; } /** * Asynchronously * The child thread asynchronous run relative to the main thread, * not blocking the child thread * * @param runnable Runnable Interface */ public static void runOnMainThreadAsync(Runnable runnable) { if (Looper.myLooper() == Looper.getMainLooper()) { runnable.run(); return; } getMainPoster().async(runnable); } /** * Synchronously * The child thread relative thread synchronization operation, * blocking the child thread, * thread for the main thread to complete * * @param runnable Runnable Interface */ public static void runOnMainThreadSync(Runnable runnable) { if (Looper.myLooper() == Looper.getMainLooper()) { runnable.run(); return; } SyncPost poster = new SyncPost(runnable); getMainPoster().sync(poster); poster.waitRun(); } public static void dispose() { if (mainPoster != null) { mainPoster.dispose(); mainPoster = null; } } }

其中就1個靜態變量HandlerPoster

然后1個初始化部份HandlerPoster_getMainPoster()這里采取同步的方式進行初始化,用于適應多線程同時調用情況;固然在初始化的時候我們傳入了

mainPoster=newHandlerPoster(Looper.getMainLooper(),20); 這里就決定了是在主線程履行的HandlerPoster,同時指定主線程單次運行時間為20毫秒。

在方法void_runOnMainThreadAsync(Runnable_runnable)中:

首先判斷調用該方法的是不是是主線程,如果是那還弄到隊列中履行干嗎?直接履行啊;如果是子線程就調用getMainPoster().async(runnable);追加到隊列中履行。

而在方法void_runOnMainThreadSync(Runnable_runnable)中:

public static void runOnMainThreadSync(Runnable runnable) { if (Looper.myLooper() == Looper.getMainLooper()) { runnable.run(); return; } SyncPost poster = new SyncPost(runnable); getMainPoster().sync(poster); poster.waitRun(); }

一樣是線程判斷,然落后行封裝,然后丟進隊列中等待履行,而在該方法中調用poster.waitRun();進行等待;直到主線程履行了SyncPost類的run方法。
最后固然留下了1個燒毀方法;媽媽說要學會清算不留垃圾:void_dispose()

OK,完成了

// "Runnable" 類實現其中 "run()" 方法 // "run()" 運行在主線程中,可在其中進行界面操作 // 同步進入主線程,等待主線程處理完成后繼續履行子線程 ToolKit.runOnMainThreadSync(Runnable runnable); // 異步進入主線程,無需等待 ToolKit.runOnMainThreadAsync(Runnable runnable);

對外就是這么兩個方法,簡單便捷??;大伙試試吧;1個字!

代碼:

ToolKit.java

HandlerPoster.java

SyncPost.java


開源項目:

Genius-Android


生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 亚洲性爰视频 | 亚洲 欧美 小说 | 国产精品高清全国免费观看 | 精品欧美一区二区在线看片 | 亚洲18卡通动漫在线播放 | 91视频啪啪| 韩国欧美 | 国产午夜精品一区二区三区不卡 | 综合自拍亚洲综合图区美腿丝袜 | 久久久亚洲精品视频 | 久久v | www.亚洲免费 | 欧美一级永久免费毛片在线 | 欧美孕妇乱大交xxxx | 岛国片在线播放 | 宅男午夜视频在线观看 | 国产亚洲在线观看 | 国产福利不卡 | 日韩久久久精品中文字幕 | 羞羞的影院 | 亚洲精品第四页中文字幕 | 波多野结衣中文字幕在线视频 | 国产一区亚洲 | 欧美成人 综合网播九公社 欧美成人18 | free欧美xxxxvideo free欧美性杂交hd | 久久v | 91九色网址 | 中文字幕视频二区 | 亚洲www| 男女xx00| free gay xxxxvideo 欧美 | 亚洲三级在线视频 | 亚洲成a v人片在线观看 | 在线亚洲不卡 | 国产一级做人爱c黑人版 | 国产高清视频在线观看不卡v | 久久精品播放 | 亚洲精品综合一区二区三区在线 | 涩涩免费播放观看在线视频 | 亚洲国产aaa毛片无费看 | 正在播放国产露脸做 |