Android的UI操作不是線程安全的(出于提高性能考慮,避免實(shí)現(xiàn)多線程同步等機(jī)制所引入的延時(shí)),若多個(gè)線程同時(shí)對(duì)UI元素進(jìn)行操作,可能導(dǎo)致線程安全問(wèn)題。因此,Android中做了嚴(yán)格的規(guī)定:只有UI主線程才能對(duì)UI進(jìn)行設(shè)置與操作。
網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、小程序制作、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了競(jìng)秀免費(fèi)建站歡迎大家使用!
在實(shí)際編程中,為了避免UI界面長(zhǎng)時(shí)間得不到響應(yīng)而導(dǎo)致的ANR(Application Not Responding)異常,通常將網(wǎng)絡(luò)訪問(wèn)、復(fù)雜運(yùn)算等一些耗時(shí)的操作被放在子線程中執(zhí)行。這就需要子線程在運(yùn)行完畢后將結(jié)果返回到主線程并通過(guò)UI進(jìn)行顯示。在Android中,是通過(guò)Handler+Loop+MessageQueue實(shí)現(xiàn)線程間通信的。
先看兩個(gè)實(shí)例:
實(shí)例1:模擬通過(guò)網(wǎng)絡(luò)下載數(shù)據(jù)并返回UI顯示。
操作過(guò)程為:1.UI線程獲得用戶請(qǐng)求。2.啟動(dòng)子線程完成網(wǎng)絡(luò)數(shù)據(jù)下載(網(wǎng)絡(luò)下載過(guò)程通過(guò)強(qiáng)制子線程休眠若干秒來(lái)模擬)。3.子線程將下載的數(shù)據(jù)返回UI線程并顯示。
主要代碼如下:
public class MainActivity extends ActionBarActivity { private Button mButton; private TextView mTextView; private Handler mHandler; private Thread mNetAccessThread; private ProgressDialog mProgressDialog; private int mDownloadCount = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_main); mButton = (Button) findViewById(R.id.btReqNet); mTextView = (TextView) findViewById(R.id.tvDownload); //設(shè)置按鈕的點(diǎn)擊事件監(jiān)聽(tīng)器 mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showProgressDialog("","正在下載..."); //啟動(dòng)子線程進(jìn)行網(wǎng)絡(luò)訪問(wèn)模擬 mNetAccessThread = new ChildTread(); mNetAccessThread.start(); } }); //繼承Handler類并覆蓋其handleMessage方法 mHandler = new Handler(){ //覆蓋Handler類的handleMessage方法 //接收子線程傳遞的數(shù)據(jù)并在UI顯示 @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: mTextView.setText((String) msg.obj); dismissProgressDialog(); break; //可以添加其他情況,如網(wǎng)絡(luò)傳輸錯(cuò)誤 //case... default: break; } } }; } class ChildTread extends Thread { @Override public void run() { //休眠6秒,模擬網(wǎng)絡(luò)訪問(wèn)延遲 try { Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } //將結(jié)果通過(guò)消息返回主線程 Message msg = new Message(); msg.what = 1; mDownloadCount ++; msg.obj = new String("第"+mDownloadCount+"次從網(wǎng)上下載的數(shù)據(jù)"); mHandler.sendMessage(msg); } }; /** * 開(kāi)啟progressDialog. * * @param title 對(duì)話框標(biāo)題. * @param content 對(duì)話框正文. */ protected void showProgressDialog(String title,String content) { mProgressDialog = new ProgressDialog(this); if(title != null) mProgressDialog.setTitle(title); if(content != null) mProgressDialog.setMessage(content); mProgressDialog.show(); } /** * 關(guān)閉progressDialog. * */ protected void dismissProgressDialog() { if(mProgressDialog != null) { mProgressDialog.dismiss(); } } }
程序運(yùn)行效果:
點(diǎn)擊下載按鈕,UI線程通過(guò)handler.sendMessage()向子線程發(fā)送消息,子線程收到消息后啟動(dòng)數(shù)據(jù)下載(通過(guò)休眠線程模擬)。
下載完畢,子線程將下載數(shù)據(jù)返回主線程并顯示。
實(shí)例2:模擬子線程向主線程發(fā)送消息。
操作過(guò)程為:1.UI線程獲得用戶輸入的消息內(nèi)容。2.通過(guò)Handler將消息發(fā)送給子線程。3.子線程獲得消息并通過(guò)Toast將內(nèi)容打印。
主要代碼如下:
public class MainActivity extends ActionBarActivity { private EditText mEditText; private Button mButton; private Handler mHandler; private Thread mChildTread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_main); mEditText = (EditText) findViewById(R.id.etEditText); mButton = (Button) findViewById(R.id.btButton); // 設(shè)置按鈕的點(diǎn)擊事件監(jiān)聽(tīng)器 mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Message msg = new Message(); msg.what = 1; msg.obj = mEditText.getText(); //將消息發(fā)送到子線程 mHandler.sendMessage(msg); mEditText.setText(""); } }); //啟動(dòng)子線程進(jìn)行msg接收 mChildTread = new ChildTread(); mChildTread.start(); } /** * 子線程為內(nèi)部類,可以直接訪問(wèn)其外部類的mHandler變量 * */ class ChildTread extends Thread { @Override public void run() { //以下三步是handler looper機(jī)制工作的固定模式 Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here switch (msg.what) { case 1: //子線程無(wú)權(quán)操作UI,只能通過(guò)Toast.makeText將收到的消息顯示 String st = msg.obj.toString(); if (st == null || st.equals("")) st = "收到的消息內(nèi)容為空"; else st = "收到來(lái)自主線程的消息:" + st; Toast.makeText(MainActivity.this, st, 6000).show(); break; //可以添加其他情況,如傳輸錯(cuò)誤 //case... default: break; } } }; Looper.loop(); } }; } 程序運(yùn)行效果:
小結(jié):Android通過(guò)Handler+Looper+MessageQueue機(jī)制實(shí)現(xiàn)線程間的通信,本文通過(guò)兩個(gè)簡(jiǎn)單的實(shí)例分別基于該機(jī)制實(shí)現(xiàn)了UI線程到子線程和子線程到UI線程的消息傳遞。下一篇博文將會(huì)對(duì)Handler Looper機(jī)制的原理進(jìn)行深入研究。
分享標(biāo)題:Android的HandlerLooperMessage機(jī)制應(yīng)用實(shí)例與詳解(一)
轉(zhuǎn)載來(lái)于:http://jinyejixie.com/article4/gggdoe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)、App設(shè)計(jì)、網(wǎng)站改版、域名注冊(cè)、網(wǎng)站導(dǎo)航、建站公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)