[Android] 多執行緒-Handler和Thread的關係

要寫Android,難懂的多執行緒一定要給他搞懂
在Android當中,如果做超過5秒被系統強制關閉
(收到Application not Responsed簡稱ANR)
onCreate()如果做超過10秒就會跳ANR

所以繁重的事情不能在onCreate()裡頭做

有沒有解決辦法?? 就是Thread 中文叫執行緒

搞不清楚?

 

用現實的例子說明好了

 

Thread ==>  做工的工人 

Runnable ==> 要做的工作事項 (工作說明書)

 

一般的Thread,工人請他來,指定工作給他做。做完就收工閃人回家

有一種Thread,他的性質比較不一樣

算是包月的那種特約駐點工人吧,要簽合約的(笑)

上班時間跟公務員一樣,就算沒事情做也要standby在那裡

這種工人他會有個經紀人幫他管要給他作的事

 

HandlerThread ==>  特約工人

Handler ==>  特約工人的經紀人

———————————————————————————-

回到程式,一般來說,Activity 執行的時候

會有個 UI Thread 或叫 main Thread
就是你程式本身原有的執行緒,管著畫面呈現…..等等事物

main Thread (或叫UI Thread)就是你的程式進入點

 

而main Thread,他也是個HandlerThread

可以給他一個Handler,做接收訊息之用

———————————————————————————-

(以下程式碼只是示意,要表達程式碼的邏輯概念

實際上在運行的時候,模擬器的畫面不會產生任何的變化

可以把它當範本使用,稍加修改)

 

 

package com.J_Test.HandlerAndThread;

 

import android.app.Activity;

import android.os.Bundle;

import android.os.Handler;

import android.os.HandlerThread;

 

publicclass main extends Activity {

    /** Called when the activity is first created. */

    //找到UI工人的經紀人,這樣才能派遣工作  (找到顯示畫面的UI Thread上的Handler)

    private Handler mUI_Handler = new Handler();

    //宣告特約工人的經紀人

    private Handler mThreadHandler;

    //宣告特約工人

    private HandlerThread mThread;

 

    @Override

    publicvoid onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

 

       

        //聘請一個特約工人,有其經紀人派遣其工人做事 (另起一個有HandlerThread)

        mThread = new HandlerThread(“name”);

        //Worker待命,等待其工作 (開啟Thread)

        mThread.start();

        //找到特約工人的經紀人,這樣才能派遣工作 (找到Thread上的Handler)

        mThreadHandler=new Handler(mThread.getLooper());

       

       

        //請經紀人指派工作名稱 r,給工人做

        mThreadHandler.post(r1);

    }

   

    //工作名稱 r1 的工作內容

    private Runnable r1=new Runnable () {

        publicvoid run() {

            // TODO Auto-generated method stub

           

            //………………………..

            //做了很多事

           

            //請經紀人指派工作名稱 r,給工人做

            mUI_Handler.post(r2);

           

        }

    };

    //工作名稱 r2 的工作內容

    private Runnable r2=new Runnable () {

        publicvoid run() {

            // TODO Auto-generated method stub

           

            //………………………..

            //顯示畫面的動作

           

        }

    };

 

    @Override

    protectedvoid onDestroy() {

        super.onDestroy();

       

        //移除工人上的工作

        if (mThreadHandler != null) {

            mThreadHandler.removeCallbacks(r1);

        }

        //解聘工人 (關閉Thread)

        if (mThread != null) {

            mThread.quit();

        }

    }

}



—————

2011.10.17更新新版,請前往:

http://j796160836.pixnet.net/blog/post/29895257

在〈[Android] 多執行緒-Handler和Thread的關係〉中有 9 則留言

  1. 不好意思~有個問題想請教您~
    我在A.Activity做了
    //宣告
    static Socket clientSocket;
    // 嘗試連接Server
    try {
    // 設定IP
    serverIp = InetAddress.getByName("10.0.2.2");
    // 設定port
    int serverPort=6000;
    // 初始socket連接
    clientSocket=new Socket(serverIp,serverPort);
    if(clientSocket.isConnected()){
    // 初始化輸出網路串流
    BufferedWriter bw = new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream()));
    // 傳送訊息到客戶端
    bw.write("#"+nickname+"\n");
    // 立即送出
    bw.flush();
    }
    } catch (IOException e) {
    // 出錯後顯示錯誤訊息
    Toast.makeText(this, "遊戲連結失敗" , Toast.LENGTH_LONG).show();
    }
    然後B.Activity的地方
    //宣告
    private Socket clientSocket=GameRoom.clientSocket;
    //啟用執行緒
    Thread t = new Thread(readData);
    t.start();
    測試的結果是
    有下面這個
    Thread t = new Thread(readData);
    t.start();
    模擬器就會錯誤
    請問大大 是不是不能這樣使用呢?
    版主回覆:(09/24/2011 05:17:56 PM)
    你要不要弄一個測試專案我測看看

  2. 清楚明暸~~讚~~ 順道一提
    //工作名稱 r2 的工作內容 <–應該是r1,不是r2
    版主回覆:(08/13/2012 06:31:41 AM)
    謝謝您,文章已修正

  3. 您好,打擾您
    想請教一下, 在onCreate 裡,Thread 啟動,
    等待訊息接受後,結束.
    我利用另一支程式,傳送文字, 只傳了一次後(假設我傳 123456789
    這一串文字.
    當然socket_service有收到文字, 但也只接收到一次,
    再接一次傳送訊息時,socket_service 就無法收到訊息.
    好像是onCreate 啟動後,就只啟動一次Thread ,
    那如果我要做到隨時等待訊息接收,那麼要如何做到呢?
    程式碼如下
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    TV_A = (TextView) findViewById( R.id.TV_A );
    TV_B = (TextView) findViewById( R.id.TV_B );
    //建立Thread
    Thread fst = new Thread(socket_server);
    //啟動Thread
    fst.start();
    }
    //取得IP
    private String getMyIp(){
    //新增一個WifiManager物件並取得WIFI_SERVICE
    //WifiManager wifi_service = (WifiManager)getSystemService(WIFI_SERVICE);
    //取得wifi資訊
    //WifiInfo wifiInfo = wifi_service.getConnectionInfo();
    //取得IP,但這會是一個詭異的數字,還要再自己換算才行
    //int ipAddress = wifiInfo.getIpAddress();
    //利用位移運算和AND運算計算IP
    //String ip = String.format("%d.%d.%d.%d",(ipAddress & 0xff),(ipAddress >> 8 & 0xff),(ipAddress >> 16 & 0xff),(ipAddress >> 24 & 0xff));
    String ip = "10.1.12.8";
    return ip;
    }
    private Runnable socket_server = new Runnable(){
    public void run(){
    handler.post(new Runnable() {
    public void run() {
    TV_A.setText("Listening…." + getMyIp());
    }
    });
    Log.d("a", "a");
    try{
    //建立serverSocket
    serverSocket = new ServerSocket(6666);
    //等待連線
    while (true) {
    //接收連線
    Log.d("a1", "a1");
    Socket client = serverSocket.accept();
    Log.d("a2", "a2");
    handler.post(new Runnable() {
    public void run() {
    TV_B.setText("Connected.");
    }
    });
    try {
    //接收資料
    Log.d("a3", "a3");
    DataInputStream in = new DataInputStream(client.getInputStream());
    line = in.readLine(); //in.readUTF();
    Log.d("a4", "a4");
    while (line != null) {
    handler.post(new Runnable() {
    public void run() {
    if (line != null) {
    TV_B.setText(line);
    }
    line = null;
    }
    });
    }
    Log.d("a5", "a5");
    client.close();
    break;
    } catch (Exception e) {
    handler.post(new Runnable() {
    public void run() {
    TV_A.setText("傳送失敗");
    }
    });
    }
    }
    }catch(IOException e){
    handler.post(new Runnable() {
    public void run() {
    TV_A.setText("建立socket失敗");
    }
    });
    }
    }
    };
    }

  4. 看了很多地方總覺得似懂非懂的
    直到看了您的文章
    才豁然開朗:)

  5. 你的比喻很很貼切,謝謝你讓我搞清楚Handler與Thread的關係

  6. 謝謝你的教學!
    我有一個疑問是為什麼
    private Handler mUI_handler = new Handler();
    可以是顯示畫面的UI Handler呢?

留言功能已關閉。