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

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > 互聯網 > 淺析Handler、Looper機制。通過自定義Handler、Looper,讓你有更直觀的了觀!

淺析Handler、Looper機制。通過自定義Handler、Looper,讓你有更直觀的了觀!

來源:程序員人生   發布時間:2014-11-21 08:26:19 閱讀次數:2686次

轉載請注明出處:http://blog.csdn.net/liu470368500/article/details/40625333

Handler、Looper。http://www.vxbq.cn/cxyms/的時候被問到的機率非常高的1個問題。固然。我說的是像我們這樣的低級。。。1般講授Handler、Looper機制的都是通過源碼去講授。這里我來通過自定義Handler、Looper。讓各位看官能有個更直觀的了解。相信有了這篇博文的基礎。再看Handler、Looper的源碼。理解起來就更容易了。


為了與安卓原生的相接軌。這里自定義的Handler-Looper使用的邏輯基本與系統原生的相1致。


先貼MyHanlder代碼:


/** * 自定義Handler * * @author lzh * */ public class MyHandler { // 用于進行線程間通訊的阻塞隊列 private BlockingQueue<MyMessage> mQueue; // 處理消息的回調 private CallBack callBack; public MyHandler(CallBack callBack) { super(); MyLooper looper = MyLooper.myLooper(); if (looper == null) { throw new RuntimeException( "在新開的線程中。創建MyHandler對象需要先調用MyLooper.prepare()方法。"); } mQueue = looper.mQueue; this.callBack = callBack; } /** * 消息接收的回調 * * @author Administrator * */ public interface CallBack { /** * 處理消息 * * @param msg */ void handleMessage(MyMessage msg); } /** * 發送消息 * * @param msg */ public void sendMessage(MyMessage msg) { msg.target = this; try { mQueue.put(msg); } catch (InterruptedException e) { } } /** * 派發消息 * * @param msg */ public void dispatchMessage(MyMessage msg) { callBack.handleMessage(msg); } }

再看MyLooper的代碼:


public class MyLooper { private static ThreadLocal<MyLooper> sThreadLocal = new ThreadLocal<MyLooper>(); private static MyLooper myLooper; /** 1個線程對應1個阻塞隊列。 */ public BlockingQueue<MyMessage> mQueue = null; private MyLooper() { super(); mQueue = new LinkedBlockingQueue<MyMessage>(); } /** * 為本線程準備對應的MyLooper對象 */ public static void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException( "Only one MyLooper may be created per thread"); } sThreadLocal.set(new MyLooper()); } /** * 獲得當前線程相對應的Looper對象 * * @return 當未調用prepare()方法時。ThreadLocal.get()方法返回的為null; */ public static MyLooper myLooper() { return sThreadLocal.get(); } /** * 這里啟動消息循環 */ public static void loop() { while (true) { try { myLooper = myLooper(); BlockingQueue<MyMessage> mQueue = myLooper.mQueue; // take()方法是個阻塞方法。線程運行到此會阻塞住。以準備接收發過來的消息 MyMessage msg = mQueue.take(); msg.target.dispatchMessage(msg); } catch (InterruptedException e) { // 當線程關閉的時候會出現此異常。此時退出循環 return; } } } }

本來安卓原生中使用的是MessageQueue。但是卻死活創建不出來。這里只有使用BlockQueue代替了。


中的ThreadLocal可能有部份朋友有點陌生。這是線程局部變量。它的set方法和get()方法比較成心思。是和線程相干的。你在哪一個線程里面set變量進去。你在哪一個線程里面get()出來的就是哪一個。所以在MyLooper中得先調用prepare()方法。先將與此線程相干的MyLooper實例創建出來加入進去。這樣便能保存1個線程只有1個Looper。相應的也只有1個阻塞隊列。


接下來看MyMessage代碼:


public class MyMessage { public int msg1; public int msg2; public int what; public Object obj; public MyHandler target; public Runnable runnable; }

生的Message由因而final標記的。而Message里面存的Handler對象又比較重要。得要依托它來指定終究的消息應當發送給哪一個Handler來接收。所以。這個也自定義了。


下面開始來測試。由于安卓不允許在UI線程中有阻塞操作。所以這里我們使用SurfaceView在子線程中畫圖來測試是不是可進行線程間通訊。


/** * 測試自定義的Handler與Looper的測試工程,由于內部有阻塞隊列。而安卓的機制是不允許此類的阻塞行動在主線程中出現。 * 所以此處用SurfaceView在子線程中進行測試 * * @author Administrator * */ public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new MySurfaceView(this)); } class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, CallBack { private static final String TAG = "MySurfaceView"; private SurfaceHolder mHolder; Thread mThread; MyHandlerCreateRunnable mRunnable; private Paint mPaint; private MyHandler handler = null; public MySurfaceView(Context context) { super(context); // 初始化holder: mHolder = getHolder(); mHolder.addCallback(this); mRunnable = new MyHandlerCreateRunnable(); mPaint = new Paint(); mPaint.setColor(Color.BLACK); mPaint.setAntiAlias(true); mPaint.setTextAlign(Align.CENTER); mPaint.setTextSize(45); new Thread(mRunnable).start(); } public MySurfaceView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public MySurfaceView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void surfaceCreated(SurfaceHolder holder) { Log.d(TAG, "==surfaceCreated=="); // mQueue = new LinkedBlockingQueue<String>(); new Thread(new MyTimerRunnable()).start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.d(TAG, "==surfaceChanged=="); } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.d(TAG, "==surfaceDestroyed=="); } @Override public void handleMessage(MyMessage msg) { synchronized (mHolder) { Canvas mCanvas = null; System.out.println("==lockCanvas=="); mCanvas = mHolder.lockCanvas();// 鎖定畫布。以后就能夠在此畫布上畫圖了。 String content = (String) msg.obj; mCanvas.drawColor(Color.WHITE); mCanvas.drawText(content, 100, 400, mPaint); mHolder.unlockCanvasAndPost(mCanvas);// } } /** * 定時發送消息的線程 * * @author Administrator * */ class MyTimerRunnable implements Runnable { int index = 0; @Override public void run() { while (true) { MyMessage msg = new MyMessage(); msg.obj = "這是第" + index + "個"; index++; handler.sendMessage(msg); if (index >= 50) { break; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 創建MyHandler的線程 * * @author Administrator * */ class MyHandlerCreateRunnable implements Runnable { @Override public void run() { MyLooper.prepare(); handler = new MyHandler(MySurfaceView.this); MyLooper.loop(); } } } }

了。代碼都貼完了。現在結合到1塊來看。在MyHandlerCreateRunnable中。我們對調用了MyLooper.prepare()方法對當前線程進行了線程局部變量保存。再創建出MyHandler對象。最后讓消息循環啟動。這時候。在此線程中如果沒有消息到來。就會在MyLooper的loop()方法中。被阻塞隊列的take()方法所阻塞。直到有消息到來。


然后我們在MyTimerRunnable中。對消息進行創建。并使用在MyHandlerCreateRunnable線程中創建的handler對象。對消息進行發送。為了方便。下面貼出局部代碼繼續分析


/** * 發送消息 * * @param msg */ public void sendMessage(MyMessage msg) { msg.target = this; try { mQueue.put(msg); } catch (InterruptedException e) { } }

此handler的sendMessage方法處。將MyHandler本身作為msg對象的1個成員變量賦值。再將些消息寄存入此消息隊列中。放入以后。MyLooper.loop()方法中的take()方法就會獲得到些msg對象并消除阻塞。繼續運行。


/** * 這里啟動消息循環 */ public static void loop() { while (true) { try { myLooper = myLooper(); BlockingQueue<MyMessage> mQueue = myLooper.mQueue; // take()方法是個阻塞方法。線程運行到此會阻塞住。以準備接收發過來的消息 MyMessage msg = mQueue.take(); msg.target.dispatchMessage(msg); } catch (InterruptedException e) { // 當線程關閉的時候會出現此異常。此時退出循環 return; } } }


運行以后可以看到。通過調用msg.target.dispatchMessage(msg)方法將此message發送給之前我們用來發送消息的MyHandler對象。


/** * 派發消息 * * @param msg */ public void dispatchMessage(MyMessage msg) { callBack.handleMessage(msg); }

接著立馬就將此消息對象發送給了自己定義的回調方法中。也就是我們handler用來處理消息的回調方法。handleMessage。

所以。弄了半天。真正用來對線程間進行通訊的其實就是1個阻塞隊列。。。相信這個結論夠簡潔明了。。。這是幾近完全仿照安卓原生的handler-looper邏輯來寫的。所以。如果你理解了這篇博客。相信更進1步的看Handler-Looper源碼會通暢很多。。。

下面提供demo下載。

點擊下載demo

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 最新在线观看精品国产福利片 | 综合免费一区二区三区 | 欧美成视频人免费淫片 | 亚洲资源最新版在线观看 | 亚洲欧洲自拍偷拍 | 亚洲狠狠狠一区二区三区 | 亚洲免费视频在线观看 | 亚洲免费视频一区二区三区 | 麻豆亚洲精品一区二区 | 日韩欧美中文字幕出 | 欧美最新一区二区三区四区 | 成人性色生活片免费看爆迷你毛片 | 国产成人精品久久一区二区三区 | 国产精品嫩草影院99av视频 | 国产精品亚洲精品爽爽 | 91精品人成在线观看 | 欧美国一级毛片片aa | 国产中文字幕视频 | 免费片子 | 伊人久久成人 | 欧美日韩永久久一区二区三区 | 五月天校园春色 | 国产亚洲小视频 | 欧美精品v国产精品v | 波多野结衣精品一区二区三区 | 欧美一区二区精品 | 国产欧美一区二区三区精品 | 日韩欧美一区二区三区在线观看 | 成年香蕉大黄美女美女 | 五月婷婷在线免费观看 | 色老头一区二区三区 | 欧美jlzz18性欧美 | 91啦中文成人 | 国产精品免费观看 | 最近最新中文字幕免费高清1 | 最近无中文字幕视频 | 午夜爱爱网站 | 国产产一区二区三区久久毛片国语 | xxx69欧美hdxxxhd| 曰本一区 | 久久成人性色生活片 |