Android Handler訊息機制,androidhandler

來源:互聯網
上載者:User

Android Handler訊息機制,androidhandler
在上一篇文章《Android AsyncTask非同步任務》中我們介紹了如何使用AsyncTask非同步處理網路通訊和UI更新。在本文中將使用Handler訊息機制來非同步處理網路通訊和UI更新。

Google參考了Windows的訊息機制,在Android系統中實現了一套類似的訊息機制。學習Android的訊息機制,有幾個概念(類)必須瞭解:
1、Message
訊息,理解為線程間通訊的資料單元。例如後台線程在處理資料完畢後需要更新UI,則可發送一條包含更新資訊的Message給UI線程。
2、Message Queue
訊息佇列,用來存放通過Handler發布的訊息,按照先進先出執行。
3、Handler
Handler是Message的主要處理者,負責將Message添加到訊息佇列以及對訊息佇列中的Message進行處理。
4、Looper
迴圈器,扮演Message Queue和Handler之間橋樑的角色,迴圈取出Message Queue裡面的Message,並交付給相應的Handler進行處理。
5、Thread
UI Thread 通常就是Main Thread,而Android啟動程式時會替它建立一個Message Queue。
每一個線程裡可含有一個Looper對象以及一個MessageQueue資料結構。

運行機理:
每個線程都可以並僅可以擁有一個Looper執行個體,訊息佇列MessageQueue在Looper的建構函式中被建立並且作為成員變數被儲存,也就是說MessageQueue相對於線程也是唯一的。Android應用在啟動的時候會預設會為主線程建立一個Looper執行個體,並藉助相關的Handler和Looper裡面的MessageQueue完成對Activities、Services、Broadcase Receivers等的管理。而在子線程中,Looper需要通過顯式調用Looper. prepare()方法進行建立。prepare()方法通過ThreadLocal來保證Looper線上程內的唯一性,如果Looper線上程內已經被建立並且嘗試再度建立"Only one Looper may be created per thread"異常將被拋出。
 
Handler在建立的時候可以指定Looper,這樣通過Handler的sendMessage()方法發送出去的訊息就會添加到指定Looper裡面的MessageQueue裡面去。在不指定Looper的情況下,Handler綁定的是建立它的線程的Looper。如果這個線程的Looper不存在,程式將拋出"Can't create handler inside thread that has not called Looper.prepare()"。
 
整個訊息處理的大致流程是:
1. 封裝Message對象(指定Handler、回呼函數和攜帶資料等);
2. 通過Handler的sendMessage()等類似方法將Message發送出去;
3. 在Handler的處理方法裡面將Message添加到Handler綁定的Looper的MessageQueue;
4. Looper的loop()方法通過迴圈不斷從MessageQueue裡面提取Message進行處理,並移除處理完畢的Message;
5. 通過調用Message綁定的Handler對象的handlerMessage()方法完成對訊息的處理。

下面仍然以彙總資料空氣品質城市空氣PM2.5指數資料介面為例來示範Handler的使用。
執行個體:HandlerDemo
運行效果:


代碼清單:
布局檔案:activity_main.xml

<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"    tools:context=".MainActivity" >    <LinearLayout         android:layout_width="match_parent"        android:layout_height="wrap_content"         android:orientation="horizontal" >        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:gravity="center"            android:text="城市:"            android:textSize="23sp" />        <EditText             android:id="@+id/city"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="3"            android:inputType="text" />    </LinearLayout>    <Button        android:id="@+id/query"        android:layout_width="match_parent"        android:layout_height="wrap_content"         android:text="查詢"         android:textSize="23sp" />        <TextView        android:id="@+id/result"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>

Java原始碼檔案:MainActivity.java
package com.rainsong.handlerdemo;import java.io.IOException;import java.net.URLEncoder;import java.util.ArrayList;import org.apache.http.HttpResponse;import org.apache.http.NameValuePair;import org.apache.http.client.HttpClient;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.DefaultHttpClient;import org.apache.http.message.BasicNameValuePair;import org.apache.http.util.EntityUtils;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity {    private static final String JUHE_URL_ENVIRONMENT_AIR_PM =                                     "http://web.juhe.cn:8080/environment/air/pm";    private static final String JUHE_APPKEY = "你申請的APPKEY值";    private static final int MSG_SUCCESS = 0;    private static final int MSG_FAILURE = 1;    EditText et_city;    Button btn_query;    TextView tv_result;    String city;    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            switch(msg.what) {            case MSG_SUCCESS:                tv_result.setText((String)msg.obj);                break;            case MSG_FAILURE:                Toast.makeText(MainActivity.this, "查詢失敗",                                    Toast.LENGTH_LONG).show();                tv_result.setText("");                break;            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        et_city = (EditText)findViewById(R.id.city);        tv_result = (TextView)findViewById(R.id.result);        btn_query = (Button)findViewById(R.id.query);        btn_query.setOnClickListener(new OnClickListener() {            public void onClick(View view) {                city = et_city.getText().toString();                if (city.length() < 1) {                    Toast.makeText(MainActivity.this, "請輸入城市名",                            Toast.LENGTH_LONG).show();                    tv_result.setText("");                    return;                }                                new Thread() {                    public void run() {                        ArrayList<NameValuePair> headerList = new ArrayList<NameValuePair>();                        headerList.add(new BasicNameValuePair("Content-Type", "text/html; charset=utf-8"));                        String targetUrl = JUHE_URL_ENVIRONMENT_AIR_PM;                        ArrayList<NameValuePair> paramList = new ArrayList<NameValuePair>();                        paramList.add(new BasicNameValuePair("key", JUHE_APPKEY));                        paramList.add(new BasicNameValuePair("dtype", "json"));                        paramList.add(new BasicNameValuePair("city", city));                        for (int i = 0; i < paramList.size(); i++) {                            NameValuePair nowPair = paramList.get(i);                            String value = nowPair.getValue();                            try {                                value = URLEncoder.encode(value, "UTF-8");                            } catch (Exception e) {                            }                            if (i == 0) {                                targetUrl += ("?" + nowPair.getName() + "=" + value);                            } else {                                targetUrl += ("&" + nowPair.getName() + "=" + value);                            }                        }                        HttpGet httpRequest = new HttpGet(targetUrl);                        try {                            for (int i = 0; i < headerList.size(); i++) {                                httpRequest.addHeader(headerList.get(i).getName(),                                                        headerList.get(i).getValue());                            }                            HttpClient httpClient = new DefaultHttpClient();                            HttpResponse httpResponse = httpClient.execute(httpRequest);                            if (httpResponse.getStatusLine().getStatusCode() == 200) {                                String strResult = EntityUtils.toString(httpResponse.getEntity());                                mHandler.obtainMessage(MSG_SUCCESS, strResult).sendToTarget();                                return;                            } else {                                mHandler.obtainMessage(MSG_FAILURE).sendToTarget();                                return;                            }                        } catch (IOException e) {                            e.printStackTrace();                        }                    }                }.start();            }        });    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        return true;    }}

API知識點
public class
Handler
extends Object

android.os.Handler

Class Overview
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

Public Constructors
Handler()
Default constructor associates this handler with the Looper for the current thread.

void handleMessage(Message msg)
Subclasses must implement this to receive messages.

final Message obtainMessage()
Returns a new Message from the global message pool.

final Message obtainMessage(int what, Object obj)
Same as obtainMessage(), except that it also sets the what and obj members of the returned Message.

public final class
Message
extends Object
implements Parcelable

android.os.Message

Class Overview
Defines a message containing a description and arbitrary data object that can be sent to a Handler. This object contains two extra int fields and an extra object field that allow you to not do allocations in many cases.

void sendToTarget()

Sends this Message to the Handler specified by getTarget().



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.