Android多線程訊息處理機制

來源:互聯網
上載者:User

標籤:

(1)主線程和ANR

主線程:UI線程,介面的修改只能在主線程中,其它線程對介面進行修改會造成異常。這樣就解決了多線程競爭UI資源的問題。

一旦主線程的代碼阻塞,介面將無法響應,這種行為就是Application Is Not Respond(ANR),應用失去響應。

如果主線程中某個事件操作時間超過5秒沒有得到響應,Android可能會彈出一個應用程式沒有響應的對話方塊。activity可能會被殺掉。

下面用執行個體來說明ANR,demo如下,這個時候按鈕就會失去響應

private Button btn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn=(Button)findViewById(R.id.button1);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {//主線程耗時操作Thread.sleep(10*1000);} catch (InterruptedException e) {e.printStackTrace();}}});}

ANR的成因和避免:1,耗時操作是不可避免的,如網路連接和網路資料的擷取,對儲存空間的讀寫,大量資料的計算,任何一種操作都有可能佔用時間,例如網路不穩定,磁碟在忙,cpu被佔用。 2,UI線程是負責事件的監聽和繪圖,因此必須保證UI線程能夠隨時響應使用者的需求,任何對UI線程的阻塞無論時間長短都會影響使用者的體驗或是導致anr,UI線程中的操作要盡量的短小,耗時操作(網路連接資料訪問等)要在單獨的線程中完成。

(2)Android的訊息機制,由於android中不可避免的要進行耗時操作,主線程阻塞會影響與使用者的互動,需要一種機制能夠通知主線程更新介面,這就是訊息機制,Looper訊息機制(主線程視角看訊息機制,訊息佇列,looper迴圈讀取訊息,進行訊息的回調),Handler訊息機制(編程視角看訊息機制)。就是Looper和Handler處理訊息機制的圖

對訊息佇列的操作只能通過Handler來進行,當Handler的sendMessage方法時就會發送一個訊息,主線程Looper就會發現訊息佇列的改變,並響應這個訊息,訊息被處理後會從隊裡移除,處理響應訊息也是由Handler來處理,handleMessage方法。這個方法是運行在主線程中的。handler中常用的方法,void handleMessage()方法,訊息發送後通過這個方法來處理,這個方法需要重寫。boolean sendEmptyMessage(int what)方法,只發送一個what值的訊息。boolean sendMesssage(Message message)發送訊息到handler,在handler中處理訊息,sendMessageDelayed(Message msg ,long s),removeMessages(int what)刪除message/取消定時的message。

 下面以一個demo來說明Handler和message的用法,demo如下

package com.example.handlerdemo;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.View;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {private static final int MESSAGE_OK=1;private static final int MESSAGE_CANCLE=2;private static final int MESSAGE_ARG1=3;private static final int MESSAGE_ARG2=4;private Handler handler=new Handler(){public void handleMessage(android.os.Message msg) {switch (msg.what) {case MESSAGE_OK:txt.setText("ok");break;case MESSAGE_CANCLE:if(msg.arg1==MESSAGE_ARG1){txt.setText("cancle"+"by user");}else{txt.setText("cancle"+"by system");}break;default:break;}};};private Button btn_ok;private Button btn_cancle;private TextView txt;private Button btn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn_cancle=(Button)findViewById(R.id.btn_cancle);btn_ok=(Button)findViewById(R.id.btn_ok);btn=(Button)findViewById(R.id.btn);txt=(TextView) findViewById(R.id.txt);btn_ok.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {/*Message msg=Message.obtain();//擷取message執行個體的正規方法msg.what=MESSAGE_OK;handler.sendMessage(msg);handler.sendEmptyMessage(MESSAGE_OK);*///sendEmptyMessage的方法handler.sendEmptyMessageDelayed(MESSAGE_OK, 10000);//延時發送訊息,還有定時發送訊息的方法}});btn_cancle.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Message msg=Message.obtain();msg.what=MESSAGE_CANCLE;msg.arg1=MESSAGE_ARG1;//message的參數。handler.sendMessage(msg);}});btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {handler.removeMessages(MESSAGE_OK);//取消發送訊息}});}}

在使用Message和Looper的時候我們還需要注意一下幾點:1,Looper和MessageQueue是在主線程建立時就會建立的,建立線程的時候是不會預設建立的,一般情況下我們是不會去直接存取者兩個對象。2,Handler必須在有Looper執行個體的情況下才能執行個體化,在建立的線程中預設是不能被執行個體化的,否則就會出錯。3,子線程預設情況下是沒有執行個體化Looper和MessageQueue對象的。

(3)Thread和Handler,handler的sendmessage()方法可以運行在其它線程中,這樣我們就何以通過Thread和Handler的結合來解決耗時操作的問題,一下我們用一個動態顯示進度條控制項的demo來說明效果如

代碼如下:

package com.example.handlerandthreaddemo;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.View;import android.widget.Button;import android.widget.ProgressBar;import android.widget.TextView;public class MainActivity extends Activity {private Button btnStart;private TextView tvDownLoad;private ProgressBar pbDownLoad;private static final int MESSAGE_NUMBER=1;private int i=0;private Handler handler=new Handler(){public void handleMessage(android.os.Message msg) {if(msg.what==MESSAGE_NUMBER){pbDownLoad.setProgress(i);tvDownLoad.setText("下載進度"+i+"%");}};};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btnStart=(Button) findViewById(R.id.btnStart);tvDownLoad=(TextView)findViewById(R.id.txtDownLoad);pbDownLoad=(ProgressBar) findViewById(R.id.pbDownLoad);btnStart.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {new Thread(){public void run() {while(i<100){try {sleep(500);i++;Message msg=Message.obtain();msg.what=MESSAGE_NUMBER;handler.sendMessage(msg);} catch (InterruptedException e) {e.printStackTrace();}}};}.start();}});}}

(4)AsyncTask線程間的非同步通訊。

       AsyncTask也是一種非同步載入機制,使用時要注意一下幾點:1,Task的執行個體必須在主線程中建立,2,execute()方法必須在主線程中調用,3,不要調用onpreExecute(),doinbackground(),onprogressUpdate(),onpostExecute()等方法。4,該執行個體化後的task只能被執行一次,重複調用會出現異常。

       AsyncTask幾種常用方法:onpreExecute()方法,該方法在執行實際的後台之前被主線程調用;doInBackground()方法,是執行耗時操作,執行在背景進程中,是抽象方法,子類必須重寫,在這個方法中調用publishprogress()方法來實現即時跟新的任務進行;onProgressUpdate()方法在publisprogress()方法被調用後,UI線程調用此方法。onPostExecute()方法是在後台操作完成後來跟新介面。下面以一個執行個體和來說明

 代碼

package com.example.asynctask;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {private Button btnStart,btn;private TextView tv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn=(Button) findViewById(R.id.button2);btnStart=(Button)findViewById(R.id.button1);tv=(TextView) findViewById(R.id.textView1);btnStart.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {MyAsyncTask myTask=new MyAsyncTask();myTask.execute();}});btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});}class MyAsyncTask extends AsyncTask<Void, Void, Void>{@Overrideprotected void onPreExecute() {tv.setText("之前");super.onPreExecute();}@Overrideprotected void onProgressUpdate(Void... values) {super.onProgressUpdate(values);String s=tv.getText().toString();tv.setText(s+"+");}@Overrideprotected Void doInBackground(Void... params) {try {for(int i=0;i<10;i++){Thread.sleep(1000);publishProgress(null);}} catch (InterruptedException e) {e.printStackTrace();}return null;}@Overrideprotected void onPostExecute(Void result) {tv.setText("完成");super.onPostExecute(result);}}}

  AsyncTask的參數以及使用方法:一個完整的asyncTask需要經曆三次傳遞參數。第一次傳參,execute()啟動時傳遞給doInBackground(),如需要複製哪個檔案,資料上傳至哪個伺服器等;第二次傳參,是doInBackground()在調用 publishProgress()時傳遞給onProgressUpdate()如:目前的下載進度,已經下載到伺服器的列表;第三次傳參,是doInBackground()在運行完以後傳遞參數給onPostExecute(),如資料擷取是否成功。

      AsyncTask定義了三種泛型型別參數分別是Params,Progress和Result,即AsyncTask<Params,Progress,Result>;Params是啟動任務執行的參數,比如Http的請求URL;Progress後台執行的百分比;Result後台執行的任務最終返回的結果,比如String,下面以一個demo來說明

如下

demo代碼如下

package com.example.asynctaskparams;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {private MyTask task;private Button btnStart,btnClose;private TextView txtContext;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btnStart=(Button)findViewById(R.id.btnStart);btnClose=(Button)findViewById(R.id.btnClose);txtContext=(TextView)findViewById(R.id.txtContext);btnStart.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {task=new MyTask();//Task發送第一個Task的參數task.execute(15);}});btnClose.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {task.cancel(true);task=null;txtContext.setText("Close");}});}@Overrideprotected void onDestroy() {if(task!=null){task.cancel(true);}super.onDestroy();}class MyTask extends AsyncTask<Integer, Integer, Boolean>{@Overrideprotected void onPreExecute() {txtContext.setText("開始");super.onPreExecute();}@Overrideprotected void onProgressUpdate(Integer... values) {//Task在此方法體中使用第二個參數txtContext.setText(""+values[0]);super.onProgressUpdate(values);}@Overrideprotected Boolean doInBackground(Integer... params) {//Task使用第一個參數for(int i=0;i<params[0];i++){//Task發送第二個參數publishProgress(i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}//Task發送第三個參數return true;}@Overrideprotected void onPostExecute(Boolean result) {//Task使用第三個參數txtContext.setText(""+result);super.onPostExecute(result);}}}

  

Android多線程訊息處理機制

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.