在上一篇文章 《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().



更多相关文章

  1. Android开发实践:由new Handler()说开去
  2. android 按两次返回键强制退出整个APP
  3. Android(安卓)ListView一些应该知道的事
  4. android利用post方式与web服务器通信
  5. Android存储路径解析
  6. 深入了解android平台的jni(一)
  7. Android(安卓)线程 thread 两种实现方法!
  8. android滑动解锁
  9. Android(安卓)异步消息处理机制 让你深入理解 Looper、Handler、

随机推荐

  1. Android(安卓)动画框架详解(第 1 部分)
  2. Android源码学习之环境搭建(Ubuntu下载And
  3. Android之Handler:实现计时器实例
  4. Android用户界面 UI组件--TextView及其子
  5. Java JDK 收费,Android(安卓)也坐不住了,程
  6. Android(安卓)APP欢迎界面小试身手
  7. 一、Bitmap的recycle问题
  8. heif android解码流程
  9. android中app的优化流程
  10. Android界面布局编程