Android多線程

Android多線程

一個Android的應用程序運行在一個獨立的進程中,運行在一個獨立的虛擬機(dvk)上。(進程名爲包名)
Android應用程序開啓後,默認開啓一個主線程(UI線程)
Activity,Service,BroadcastReceive組件運行在主線程中
Android 應用程序退出後,保留空UI線程,可以加快應用程序啓動速度。
用戶不能再UI主線程中做耗時的操作,一旦操作超過5s,應用程序拋出一個ANR(application not respond)

如何避免ANR錯誤?
將耗時的操作放入到子線程中。(耗時的操作包括:長時間的休眠,計數,聯網,複雜的運算)
只有主線程才能操作Widget控件。
如果在子線程中出現操作Widget控件,系統拋出CalledFromWrongThreadException異常。
系統爲什麼要這麼做?
避免出現同步問題。

Handler機制

作用
主要爲了解決非UI線程中不能更新Widget控件的問題
Handler機制剖析
子線程發送消息給底層的消息隊列。
handler.sendMessage(msg)
主線程查詢消息隊列,處理消息對象。
handlerMessage(msg)
MessageQueue 消息隊列
負責存儲消息對象
Looper
給UI線程安排代碼,一個UI線程只能有一個Looper對象,否則多個Looper對象都在UI線程上安排代碼,解決衝突就是個大問題。
Looper對象會線性安排在UI線程上執行的代碼,它通過一個隊列管理各個Handler對象提交的代碼。
Message消息對象
//從消息池中獲取消息對象
Message msg = handler.obtainMessage();
//在消息對象上綁定int類型數據
msg.arg1 = count;
//在消息對象上綁定其它類型數據
msg.setData(Bundle); //Bundler爲數據集(類似於HashMap容器)

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
/**
 * @author Administrator
 * 事件驅動的應用程序
 */
public class MainActivity extends Activity implements OnClickListener {
    Button btnStart;
    TextView tv;
    int count = 0;
    boolean isRun;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnStart = (Button) findViewById(R.id.button1);
        btnStart.setOnClickListener(this);
        findViewById(R.id.button2).setOnClickListener(this);
        tv = (TextView) findViewById(R.id.textView1);
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        if(v.getId() == R.id.button1){  
            btnStart.setEnabled(false);
            count = 0;
            isRun = true;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    // 修改Widget控件的值
                    // tv.setText(String.valueOf(count));
                    while (isRun) {
                        count++;
                        // 創建消息對象
                        Message msg = new Message();
                        msg.arg1 = count;
                        //設置消息類型
                        msg.what = 2;
                        // 發送消息 (發給底層的消息隊列)
                        handler.sendMessage(msg);

                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }

                    handler.sendEmptyMessage(1);
                }
            }).start();
        }else if(v.getId() == R.id.button2){    
            isRun = false;  
        }
    }
    Handler handler = new Handler(){

        //如果消息隊列中有消息,系統自動調用該方法處理消息
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            if(msg.what == 2){
                int count = msg.arg1;
                tv.setText(String.valueOf(count));
            }else if(msg.what == 1){
                //修改按鈕屬性
                btnStart.setEnabled(true);
            }
        }
    };
}

向消息隊列發送消息,1000毫秒後執行Runnable對象中的代碼。

myHandler.postDelayed(new Runnable() {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        Log.e("Test", "thread name = "+Thread.currentThread().getName());
    }
}, 1000);

異步任務(Async Task)

概念
封裝多線程和Handler機制。給用戶提供重寫接口的方式,不需要用戶手動創建子線程和Handler對象。
異步任務的優點
Handler模式需要爲每一個任務創建一個新的線程,任務完成後通過Handler實例向UI主線程發送消息,完成界面的更新,這種方式對於整個過程的控制比較精細,但是也有缺點,代碼臃腫,在多個任務同時執行時,不易對線程進行精確的控制。爲了簡化操作,Android1.5提供了一個工具類AsyncTask,它是創建異步任務變的更加簡單,不再需要編寫任務線程和Handler實例就可完成任務。
異步任務的侷限性
多個異步任務不能同時執行,在某個時間內,只能執行一個異步任務。
執行異步任務的步驟:

  • 1 execute(Params … params),執行一個異步任務,需要我們在代碼中調用此方法,觸發異步任務的執行。
  • 2 onPreExecute(),在execute(Params… params
    )被調用後立即執行,一般用來在執行後臺任務前對UI做一些標記。
  • 3 doInBackground(Params…
    params),在onPreExecute()完成後立即執行,用於執行較爲費時的操作,此方法將接受輸入參數和返回計算結果在執行過程中可以調用publishProgress(Progress…values)來更新進度信息。作用在非UI線程上。
  • 4 onProgressUpdate(Progress… values),在調用publishProgress(Progress…
    values)時,此方法被執行,直接將進度信息更新到UI組件上。
  • 5 onPostExecute(Result
    result)當後臺操作結束時,此方法將被調用,計算結果講座爲參數傳遞到方法中,直接將結果顯示到UI組件上。
import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;

//Params 執行異步任務時,傳入的參數
//Progress 異步任務的進度
//Result 結果
public class MyTask extends AsyncTask<Void, Integer, Void> {

    TextView tv;
    public MyTask(TextView tv) {
        // TODO Auto-generated constructor stub
        this.tv = tv;
    }

    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        super.onPreExecute();
        Log.d("Test", "onPre");
    }
    //該方法運行在非UI線程中
    //該方法中放耗時操作
    @Override
    protected Void doInBackground(Void... params) {
        // TODO Auto-generated method stub
        int count = 0;
        while(!isCancelled() && count < 10){
            count++;
            //發佈進度
            //觸發系統自動調用onProgressUpdate
            //相當於handler.sendMessage()
            publishProgress(count);

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return null;
    }
    //相當於handlerMessage()
    //該方法運行在UI線程中
    @Override
    protected void onProgressUpdate(Integer... values) {
        // TODO Auto-generated method stub
        super.onProgressUpdate(values);

        if(isCancelled()){
            return;
        }
        //操作UI控件
        int count = values[0];
        tv.setText(String.valueOf(count));
    }

    //該放在在取消異步任務之後運行
    @Override
    protected void onCancelled() {
        // TODO Auto-generated method stub
        super.onCancelled();
    }

    @Override
    protected void onPostExecute(Void result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        Log.d("Test", "onPost");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章