Handler 处理器,主要接受子线程发送的数据, 并用此数据配合主线程更新UI。

.net里面有httphandler这个概念,不过.net里面,这个httphandler的作用是:所有的http请求在服务器处理之前进行拦截同时做相应的处理,而android里面这个Handler,个人理解就是起桥梁的作用,When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it,它和创建它的线程或消息队列绑定。在主线程里面可以创建子线程,然后子线程任务处理完了,怎么通知主线程呢?这个时候就靠它了。它告诉主线程,某个子线程已经处理完了,然后在主线程里面做出相应的回应。使用Handler就是实现一段时间内,让系统在一段时间内异步处理多个任务,这个和AsyncTask有异曲同工之妙,Android开发网推荐大家使用AsyncTask代替Thread+Handler的方式,不仅调用上更为简单,经过实测更可靠一些,Google在Browser中大量使用了异步任务作为处理耗时的I/O操作,比如下载文件、读写数据库等等,它们在本质上都离不开消息,但是 AsyncTask相比Thread加Handler更为可靠,更易于维护,但AsyncTask缺点也是有的比如一旦线程开启即 dobackground方法执行后无法给线程发送消息,仅能通过预先设置好的标记来控制逻辑,当然可以通过线程的挂起等待标志位的改变来通讯,对于某些应用Thread和Handler以及Looper可能更灵活。

一、理论知识

public class Handler extends Object

 

java.lang.Object

   ↳ android.os.Handler

Known Direct Subclasses

AsyncQueryHandler, AsyncQueryHandler.WorkerHandler, HttpAuthHandler, SslErrorHandler

AsyncQueryHandler A helper class to help make handling asynchronous ContentResolver queries easier. 

AsyncQueryHandler.WorkerHandler  

HttpAuthHandler HTTP authentication request that must be handled by the user interface. 

SslErrorHandler SslErrorHandler: class responsible for handling SSL errors. 

 

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.

 

There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

 

Scheduling messages is accomplished with the post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long) methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler's handleMessage(Message) method (requiring that you implement a subclass of Handler).

 

When posting or sending to a Handler, you can either allow the item to be processed as soon as the message queue is ready to do so, or specify a delay before it gets processed or absolute time for it to be processed. The latter two allow you to implement timeouts, ticks, and other timing-based behavior.

 

When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler. This is done by calling the same post or sendMessage methods as before, but from your new thread. The given Runnable or Message will then be scheduled in the Handler's message queue and processed when appropriate.

 

二、实践操作

我们实现的功能是:假设在一个游戏下载页面,用户可以浏览游戏,然后选中一个或多个开始下载到手机,这个下载的过程我们就可以新起一个线程,让它下载,下载后通知用户已经下载成功。

第一步、设计页面handler.xml

 

<?xml version="1.0" encoding="utf-8"?> 

<RelativeLayout

  xmlns:android="​​http://schemas.android.com/apk/res/android​​"

  android:orientation="vertical"

  android:layout_width="fill_parent"

  android:layout_height="fill_parent">

    <ImageView  android:layout_width="wrap_content" android:layout_height="wrap_content"android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_marginTop="22dp"android:id="@+id/imgProduct"></ImageView>

    <TextView android:layout_height="wrap_content" android:id="@+id/tvTitle"android:layout_width="wrap_content" android:text="游戏下载" android:layout_below="@+id/imgProduct"android:layout_alignParentLeft="true"></TextView>

    <TextView android:layout_height="wrap_content" android:id="@+id/tvDescription"android:layout_width="wrap_content" android:text="愤怒的小鸟     切西瓜" android:layout_below="@+id/tvTitle"android:layout_alignParentLeft="true" android:layout_marginTop="40dp"></TextView>

    <Button android:layout_height="wrap_content" android:layout_width="wrap_content"android:id="@+id/buttonbuy" android:text="@string/download" android:layout_below="@+id/tvDescription"android:layout_alignParentLeft="true" android:layout_marginTop="19dp"></Button>

</RelativeLayout>

 

第二步、设计Activity HandlerActivity.java

 

/**

 *

 */

package com.figo.helloworld;

 

import android.app.Activity;

import android.app.ProgressDialog;

import android.content.Intent;

import android.os.Bundle;

import android.os.Handler;

import android.os.Looper;

import android.os.Message;

import android.util.Log;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.Toast;

 

/**

 * @author zhuzhifei

 *

 */

public class HandlerActivity extends Activity implements OnClickListener {

    Button button;

    MyHandler myHandler;

    private ProgressDialog pd;

 

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.handler);  

        button = (Button) findViewById(R.id.buttonbuy);

        button.setOnClickListener(this);

        myHandler = new MyHandler();

 

        // 当创建一个新的Handler实例时, 它会绑定到当前线程和消息的队列中,开始分发数据

        // Handler有两个作用, (1) : 定时执行Message和Runnalbe 对象

        // (2): 让一个动作,在不同的线程中执行.

 

        // 它安排消息,用以下方法

        // post(Runnable)

        // postAtTime(Runnable,long)

        // postDelayed(Runnable,long)

        // sendEmptyMessage(int)

        // sendMessage(Message);

        // sendMessageAtTime(Message,long)

        // sendMessageDelayed(Message,long)

 

        // 以上方法以 post开头的允许你处理Runnable对象

        // sendMessage()允许你处理Message对象(Message里可以包含数据,)

 

    }

    //按钮事件

    @Override

    public void onClick(View v) {

        // TODO Auto-generated method stub

        // 构建一个下载进度条

        pd = ProgressDialog.show(HandlerActivity.this, "下载文件", "正在下载……");

 

        Log.i("HandlerActivity", "MyThread()-->"

                + Thread.currentThread().getName());

 

        MyThread m = new MyThread();

        new Thread(m).start();

    }

 

    /**

     * 接受消息,处理消息 ,此Handler会与当前主线程一块运行

     * */

 

    class MyHandler extends Handler {

        public MyHandler() {

        }

 

        public MyHandler(Looper L) {

            super(L);

        }

 

        // 子类必须重写此方法,接受数据

        @Override

        public void handleMessage(Message msg) {

            // TODO Auto-generated method stub

            Log.d("MyHandler", "handleMessage......");

            super.handleMessage(msg);

            // 此处可以更新UI

            Bundle b = msg.getData();

            String result = b.getString("result");

            Log.d("result", result);

            pd.dismiss();

            if ("ok".equals(result)) {

                Toast.makeText(HandlerActivity.this, "恭喜您,下载成功", Toast.LENGTH_LONG).show();

            }else

            {

                Toast.makeText(HandlerActivity.this, "下载失败,请您重新再试", Toast.LENGTH_LONG).show();

            }

 

        }

    }

    //创建子线程

    class MyThread implements Runnable {

        public void run() {

 

            try {

                Log.i("MyThread", "MyThread-->"

                        + Thread.currentThread().getName());

                Thread.sleep(10000); //这里模拟下载,具体的下载逻辑今后专门写一篇文章

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

 

            Log.d("thread.......", "mThread........");

            Message msg = new Message();

            Bundle b = new Bundle();// 存放数据

            b.putString("result", "ok");

            msg.setData(b);

 

            HandlerActivity.this.myHandler.sendMessage(msg); // 向Handler发送消息,通知主线程更新UI

        }

 

    }

}

 

第三步、AndroidManifest.xml注册Activity

    <activity android:name=".HandlerActivity">

           <intent-filter>

              <action android:name="android.intent.action.MAIN" />

              <category android:name="android.intent.category.LAUNCHER" />

           </intent-filter>

    </activity>

第四步、运行效果

Handler让主线程和子线程进行通信_sed