1. 程式人生 > >Android開發學習之路--非同步訊息Handler,Message,Looper和AsyncTask之初體驗

Android開發學習之路--非同步訊息Handler,Message,Looper和AsyncTask之初體驗

    在簡易音樂播放器中,用了Handler,也沒有過多地去研究學習,這裡再學習下android下的非同步訊息處理機制。這裡用了Handler主要是線上程中不能更新UI,而需要通過Handler才可以。關於非同步訊息處理有幾個概念。

    1、Message:訊息,執行緒間通訊的資料單元。例如後臺要下載歌曲然後下載完成要更新ui,則可以傳送一條包含更新資訊的Message給UI執行緒。

    2、MessageQueue:訊息佇列,用來存放所有通過Handler釋出的訊息,因為是佇列,所以是先進先出的。

    3、Handler:Message的主要處理者,負責將Message新增到訊息佇列以及對訊息佇列中的Message進行處理。

    4、Looper:迴圈管理MessageQueue,迴圈取出MessageQueue中的Message,並交給相應的Handler進行處理。

    5、執行緒:UI thread是main thread,android啟動程式時會替他建立一個MessageQueue。每一個執行緒裡可含有一個Looper物件以及一個MessageQueue資料結構。

     下面來個例子吧還是,新建工程HandlerTest,編寫簡單佈局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:layout_margin="10dp"
    tools:context="com.example.jared.handlertest.MainActivity">

    <EditText
        android:id="@+id/inputContent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="輸入要改變的內容"/>

    <Button
        android:id="@+id/changeViewContent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Change The ViewContent"
        android:textAllCaps="false"/>

    <TextView
        android:id="@+id/testHandler"
        android:text="I am old!!!"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:textSize="22dip"
        android:layout_gravity="center"/>

</LinearLayout>

    這裡輸入內容,按button,改變TextView的內容。編寫MainActivity程式碼如下:
package com.example.jared.handlertest;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    public static final int UPDATA_VIEW = 1;

    private TextView textView;
    private Button changeContent;
    private EditText inputContent;

    private Thread  mThread;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATA_VIEW:
                    String mInputContent = inputContent.getText().toString();
                    textView.setText(mInputContent);
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView)findViewById(R.id.testHandler);
        inputContent = (EditText)findViewById(R.id.inputContent);

        changeContent = (Button)findViewById(R.id.changeViewContent);
        changeContent.setOnClickListener(new myOnClickListener());
    }

    private class myOnClickListener implements View.OnClickListener {
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.changeViewContent:
                    mThread = new Thread(runnable);
                    mThread.start();
                    break;
                default:
                    break;
            }
        }
    }

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            Message message = new Message();
            message.what = UPDATA_VIEW;
            mHandler.sendMessage(message);
        }
    };
}

    這裡先new了一個Handler,handleMessage方法處理髮送的Message,Thread裡面傳送message,然後更新TextView的內容,執行如下:

           

    基本的Handler已經完成了,下面再學習下AsyncTask。

    AsyncTask是方便編寫後臺執行緒和UI執行緒的輔助類。它內部的實現是一個執行緒池,每個後臺會提交到執行緒池中去執行。AsyncTask有三個模板函式:

    1、Params:傳遞給後臺任務的引數型別。

    2、Progress:後臺計算執行過程中,進步的單位型別。

    3、Result:後臺執行返回的結果的型別。

    當標示不需要的型別的時候,只要用Void就行了。

    AsyncTask需要重寫5個方法,分別是:

    1、onPreExecute方法:準備執行,該回調函式在任務被執行之後立即由UI執行緒呼叫,一般可以顯示進度條。

    2、doInBackground(Params ...)方法:正在後臺執行,通常在這裡執行耗時的後臺計算,計算結果返回給函式,這裡如果AsyncTask的第三個引數是Void的話不需要返回,這裡不能更新UI,但是可以呼叫publishProgress(Progress ...)方法完成。

    3、onProgressUpdate(Progress ...)方法:進度更新,UI執行緒在publishProgress(Progress ...)方法呼叫完成後被呼叫,一般動態顯示一個進度。

    4、onPostExecute(Result)方法:完成後臺任務,會返回,這裡可以進行些UI的操作,比如提醒任務執行的結果,以及關閉掉進度條對話方塊等。

    5、onCancelled方法:取消任務,在呼叫AsyncTask的cancel()方法的時候呼叫。

    下面通過AsyncTask的方式來進行上面的例子,Handler的程式碼就沒有刪除掉了,程式碼如下:

package com.example.jared.handlertest;

import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    public static final int UPDATA_VIEW = 1;

    private TextView textView;
    private Button changeContent;
    private EditText inputContent;

    private Thread  mThread;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATA_VIEW:
                    String mInputContent = inputContent.getText().toString();
                    textView.setText(mInputContent);
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView)findViewById(R.id.testHandler);
        inputContent = (EditText)findViewById(R.id.inputContent);

        changeContent = (Button)findViewById(R.id.changeViewContent);
        changeContent.setOnClickListener(new myOnClickListener());
    }

    private class myOnClickListener implements View.OnClickListener {
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.changeViewContent:
                   // mThread = new Thread(runnable);
                   // mThread.start();
                    changeViewContentTask  task = new changeViewContentTask();
                    task.execute();
                    break;
                default:
                    break;
            }
        }
    }

    class changeViewContentTask extends AsyncTask<Void, Integer, Boolean> {
        @Override
        protected Boolean doInBackground(Void... voids) {
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
        }

        @Override
        protected void onPostExecute(Boolean b) {
            String mInputContent = inputContent.getText().toString();
            textView.setText(mInputContent);
        }

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected void onCancelled() {
        }
    }

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            Message message = new Message();
            message.what = UPDATA_VIEW;
            mHandler.sendMessage(message);
        }
    };
}
    這裡例項化一個task,然後task.execute();就可以執行了,效果如上就不添圖了。