摘要:機(jī)制處理的個(gè)關(guān)鍵對(duì)象線程之間傳遞的消息,可以攜帶一些簡(jiǎn)單的數(shù)據(jù)供子線程與主線程進(jìn)行交換數(shù)據(jù)。解決方法子線程通過(guò)發(fā)送消息給主線程,讓主線程處理消息,進(jìn)而更新。
極力推薦文章:歡迎收藏
Android 干貨分享
本篇文章主要介紹 Android 開發(fā)中的部分知識(shí)點(diǎn),通過(guò)閱讀本篇文章,您將收獲以下內(nèi)容:
Handler 消息處理機(jī)制原理
Handler 機(jī)制處理的4個(gè)關(guān)鍵對(duì)象
Handler常用方法
子線程更新UI 異常處理
主線程給子線程發(fā)送消息的方法
子線程給主線程發(fā)送消息的方法
主、子 線程 互發(fā)消息方法
子線程方法中調(diào)用主線程更新UI的方法
Handler是 Android中用來(lái)更新UI 的一套消息處理機(jī)制。Handler 允許線程間發(fā)送Message或Runnable對(duì)象進(jìn)行通信。在Android中UI修改只能通過(guò)UI Thread,子線程不能更新UI。如果子線程想更新UI,需要通過(guò) Handler 發(fā)送消息給主線程,進(jìn)而達(dá)到更新UI的目的。
Handler 簡(jiǎn)介 繼承關(guān)系如下:java.lang.Object ? android.os.Handler1. Handler 消息處理機(jī)制原理
當(dāng)Android 應(yīng)用程序創(chuàng)建的時(shí)候,系統(tǒng)會(huì)給每一個(gè)進(jìn)程提供一個(gè)Looper ,Looper 是一個(gè)死循環(huán),它內(nèi)部維護(hù)一個(gè)消息隊(duì)列,Looper 不停的從消息隊(duì)列中取Message,取到的消息就發(fā)送給handler,最后Handler 根據(jù)接收的消息去修改UI等。
2. Handler 機(jī)制處理的4個(gè)關(guān)鍵對(duì)象 1.Message線程之間傳遞的消息,可以攜帶一些簡(jiǎn)單的數(shù)據(jù)供子線程與主線程進(jìn)行交換數(shù)據(jù)。
2.Message Queue存放通過(guò)Handler 發(fā)送的 Message 的消息隊(duì)列,每一個(gè)線程只有一個(gè)消息隊(duì)列。
3.Handler消息處理者,主要用于發(fā)送跟處理消息。
主要功能:
發(fā)送消息SendMessage()
處理消息 HandleMessage()
內(nèi)部包含一個(gè)死循環(huán)的MessageQueue,用于存儲(chǔ)handler 發(fā)送的Message,Looper則是不斷的從消息隊(duì)列中取消,如果有消息就取出發(fā)送給Handler 處理,沒有則阻塞。
總結(jié):Handler 負(fù)責(zé)發(fā)送Message到Message Queue,Looper負(fù)責(zé)從Message Queue 遍歷Message ,然后直接把遍歷的消息回傳給Handler 自己,通過(guò)Handler 自身的handleMessage處理更新UI等操作。
3. Handler常用方法 1.Runnable對(duì)象post(Runnable)
使用方法舉例:
public void BtnRunnableMethod(View view) { // 1.Runnable 對(duì)象 RunnableHandlderMethod(); } /** * Runnable 對(duì)象更新 UI * **/ private Handler mRunnableHandler = new Handler(); public void RunnableHandlderMethod() { new Thread() { @Override public void run() { try { Thread.sleep(1000); mRunnableHandler.post(new Runnable() { @Override public void run() { ((Button) findViewById(R.id.btn_runnable)) .setText("Runnable"); } }); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); }
postAtTime(Runnable, long)
postDelayed(Runnable, long)
2. Message 對(duì)象sendEmptyMessage(int)
使用方法舉例:
public void BtnMessageThreadMethod(View view) { // 2.Message 對(duì)象 new MessageHandlerThreadMethod("子線程不能更新UI").start(); } /** * Message 對(duì)象舉例 * ***/ private int mCount = 0; private Handler mMessageHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); ((Button) findViewById(R.id.btn_thread)).setText("" + mCount); } }; class MessageHandlerThreadMethod extends Thread { String mString; public MessageHandlerThreadMethod(String str) { mString = str; } @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); } catch (Exception e) { } mCount++; mMessageHandler.sendEmptyMessage(0); } } }
sendMessage(Message)
使用方法舉例:
public void BtnMessageObjMethod(View view) { HandlerMessageObjMethods(); } /*** * handler sendmessage 處理方法 * **/ private Handler mHandlerMessageObj = new Handler() { @Override public void handleMessage(Message msg) { ((Button) findViewById(R.id.btn_message)).setText("arg1:" + msg.arg1 + " " + msg.obj); } }; private void HandlerMessageObjMethods() { new Thread() { @Override public void run() { try { Thread.sleep(1000); // Message message = new Message(); Message message = mHandlerMessageObj.obtainMessage(); message.arg1 = 100; Person person = new Person(); person.name = "Lucy"; person.age = 12; message.obj = person; mHandlerMessageObj.sendMessage(message); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); } class Person { public int age; public String name; public String toString() { return "Name=" + name + " Age=" + age; } }
sendMessageAtTime(Message, long),
sendMessageDelayed(Message, long)
3.接收、處理MessagehandleMessage(Message)
使用方法舉例:
private Handler mMessageHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); ((Button) findViewById(R.id.btn_thread)).setText("" + mCount); } };4. 子線程更新UI 異常處理
子線程不能更新UI,如果在子線程中更新UI,會(huì)出現(xiàn)CalledFromWrongThreadException 異常。
CalledFromWrongThreadException
解決方法:子線程通過(guò)Handler 發(fā)送消息給主線程,讓主線程處理消息,進(jìn)而更新UI。
5. 主線程給子線程發(fā)送消息的方法此例子中子線程通過(guò)Looper不斷遍歷主線程發(fā)送的消息,Looper 使用方法如下:
準(zhǔn)備Looper 輪詢器
Looper.prepare();
Handler 處理遍歷消息
Handler mHandler = new Handler()
遍歷消息隊(duì)列
Looper.loop();
Looper 使用方法如下:
// 自定義 Loop 線程 ---> 不停的處理主線程發(fā)的消息 class ChildLooperThread extends Thread { @Override public void run() { // 1.準(zhǔn)備成為loop線程 Looper.prepare(); // 2.處理消息 mMainHandler = new Handler() { // 處理消息 public void handleMessage(Message msg) { super.handleMessage(msg); ... ... } }); } }; // 3.Loop循環(huán)方法 Looper.loop(); } }
主線程發(fā)送消息給子線程 的使用例子如下:
啟動(dòng) 子線程,并再啟動(dòng)后發(fā)送消息
public void BtnMainMessageMethod(View view) { // 點(diǎn)擊主線程 按鈕,啟動(dòng)子線程,并在子線程啟動(dòng)后發(fā)送消息 Message msg = new Message(); msg.obj = "主線程:這是我攜帶的信息"; if (mMainHandler != null) { // 2.主線程發(fā)送消息 mMainHandler.sendMessage(msg); } else { Toast.makeText(getApplicationContext(), "開啟子線程輪詢消息,請(qǐng)?jiān)俅吸c(diǎn)擊發(fā)送消息", Toast.LENGTH_SHORT).show(); // 1.開啟輪詢線程,不斷等待接收主線成消息 new ChildLooperThread().start(); } }
子線程啟動(dòng),不停的變量主線程發(fā)送的消息
private Handler mMainHandler; String mMainMessage; // 自定義 Loop 線程 ---> 不停的處理主線程發(fā)的消息 class ChildLooperThread extends Thread { @Override public void run() { // 1.準(zhǔn)備成為loop線程 Looper.prepare(); // 2.處理消息 mMainHandler = new Handler() { // 處理消息 public void handleMessage(Message msg) { super.handleMessage(msg); mMainMessage = (String) msg.obj; Log.i("TAG", "子線程:從主線程中接受的消息為: " + mMainMessage); // 使用 runOnUiThread 在主線程中更新UI runOnUiThread(new Runnable() { @Override public void run() { ((Button) findViewById(R.id.btn_main_message)) .setText(mMainMessage); } }); } }; // 3.Loop循環(huán)方法 Looper.loop(); } }6. 子線程給主線程發(fā)送消息的方法
1.子線程發(fā)送消息給主線程方法
public void BtnChildMessageMethod(View view) { new Thread() { public void run() { while (mCount < 100) { mCount++; try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } /** * 利用handler 對(duì)象發(fā)送消息 Message msg=Message.obtain(); Message * msg=new Message(); 獲取一個(gè)消息對(duì)象message * */ Message msg = Message.obtain(); // 消息標(biāo)記 msg.what = 1; // 傳遞整型值msg.obj="傳遞object數(shù)據(jù)" msg.arg1 = mCount; Log.i("TAG", "count 值=" + mCount); if (mhandler != null) { mhandler.sendMessage(msg); } } } }.start(); }
2.主線程接收并處理消息的方法
// 定義一個(gè)handler 主線程 接收子線程發(fā)來(lái)的信息 private Handler mhandler = new Handler() { // 處理消息的方法 public void handleMessage(android.os.Message msg) { switch (msg.what) { case 1: int value = msg.arg1; Log.i("TAG", "value值=" + value); ((Button) findViewById(R.id.btn_child_message)).setText("當(dāng)前值=" + value); break; default: break; } } };7. 主、子 線程 互發(fā)消息方法
主要實(shí)現(xiàn)主、子線程每隔1s中通信一次
實(shí)現(xiàn)打印Log如下:
實(shí)現(xiàn)方法如下:
啟動(dòng)子線程并發(fā)送給主線程消息
public void BtnMainChildMessageMethod(View view) { // 創(chuàng)建 名稱為currentThread 子線程 HandlerThread mChildThread = new HandlerThread("ChildThread"); mChildThread.start(); mChildHandler = new Handler(mChildThread.getLooper()) { @Override public void handleMessage(Message msg) { Log.i("TAG", "主線程對(duì)我說(shuō):" + msg.obj); // 子線程攜帶的消息 Message message = new Message(); message.obj = Thread.currentThread() + "我是子線程,小樣,讓我聽你的沒門"; // 向主線程發(fā)送消息 mainhandler.sendMessageDelayed(message, 1000); } }; // 主線成發(fā)送空消息,開啟通信 mainhandler.sendEmptyMessage(1); }
2.主線程接收并處理子線程發(fā)送的消息
// 創(chuàng)建主線程 private Handler mainhandler = new Handler() { @Override public void handleMessage(Message msg) { Log.i("TAG", "子線程對(duì)我說(shuō):" + msg.obj); // 主線成攜帶的消息內(nèi)容 Message message = new Message(); message.obj = Thread.currentThread() + "我是主線程:小子你得聽我的。"; // 向子線程發(fā)送消息 mChildHandler.sendMessageDelayed(message, 1000); } };8.子線程方法中調(diào)用主線程更新UI的方法 Activity 中 可以使用 runOnUiThread(Runnable)
// 使用 runOnUiThread 在主線程中更新UI runOnUiThread(new Runnable() { @Override public void run() { ((Button) findViewById(R.id.btn_main_message)) .setText(mMainMessage); } });子線程使用 Handler.post(Runnable)
mRunnableHandler.post(new Runnable() { @Override public void run() { ((Button) findViewById(R.id.btn_runnable)) .setText("Runnable"); } });View.post()
((Button) findViewById(R.id.btn_runnable)).post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub ((Button) findViewById(R.id.btn_runnable)).setText("View.post()方法使用"); } });Handler.sendMessage(Message)
public void BtnMainMessageMethod(View view) { // 點(diǎn)擊主線程 按鈕,啟動(dòng)子線程,并在子線程啟動(dòng)后發(fā)送消息 Message msg = new Message(); msg.obj = "主線程:這是我攜帶的信息"; if (mMainHandler != null) { // 2.主線程發(fā)送消息 mMainHandler.sendMessage(msg); } }9.移除Handler 發(fā)送的消息方法
1.移除 handler 發(fā)送的所有消息
private Handler mChildHandler; mChildHandler.removeCallbacksAndMessages(null);
2.移除 指定消息
private Handler mainhandler; mainhandler.removeMessages(what);
至此,本篇已結(jié)束,如有不對(duì)的地方,歡迎您的建議與指正。同時(shí)期待您的關(guān)注,感謝您的閱讀,謝謝!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/75832.html
摘要:在級(jí)事件中定義了個(gè)鼠標(biāo)事件,分別是。取消鼠標(biāo)事件的默認(rèn)行為還會(huì)影響其他事件,因?yàn)槭髽?biāo)事件與其他事件是密不可分的關(guān)系。同樣的,和支持這個(gè)事件。兼容各個(gè)瀏覽器的事件監(jiān)聽對(duì)象該對(duì)象封裝了和級(jí)事件的常用事件函數(shù)。 概述 鼠標(biāo)事件是web開發(fā)中最常用的一類事件,畢竟鼠標(biāo)還是最主要的定位設(shè)備。在DOM3級(jí)事件中定義了9個(gè)鼠標(biāo)事件,分別是:click,dbclick,mousedown,mousee...
我們?cè)趎ew Handler()時(shí)候,實(shí)際上調(diào)用的是兩個(gè)參數(shù)的構(gòu)造方法,我們看下 public Handler() { this(null, false); } public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { fina...
閱讀 3275·2021-10-14 09:42
閱讀 3592·2019-08-26 13:56
閱讀 3560·2019-08-26 11:59
閱讀 973·2019-08-23 18:00
閱讀 2242·2019-08-23 17:51
閱讀 3563·2019-08-23 17:17
閱讀 1504·2019-08-23 15:11
閱讀 5340·2019-08-23 15:05