Android Handler

最近经常用到Handler,今天复习了一下,知识还是要经常复习的哈,温故知新!

Handler主要接受子线程数据,并用此数据配合主线程更新UI。

Handler的作用:

(1)发送和处理消息(Message)。

(2)发送和处理Runnable对象。

  对于Android里的消息处理,涉及到Handler,Looper,Message,MessageQueue等概念,先理顺这些概念。

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。

MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO(队列先进先出)规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

Looper:一个线程可以产生一个Looper对象,用来管理MessageQueue,它就像一个消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。

一、发送和处理消息(Message)

Handler myHandler = new Handler() {

            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == 1) {
                    
                }
            }

        };
        // 第一种 调用myHandler.obtainMessage() 获得的Message已经跟myHandler绑定
        Message msg1 = myHandler.obtainMessage();
        // 直接调用 sendToTarget() 就可以把消息送入队列,等待Handler执行
        msg1.sendToTarget();
        // 第二种 直接用Message的构造函数
        Message msg2 = new Message();
        // 调用Handler 实例的 sendMessage()方法把消息送入队列,等待Handler执行
        myHandler.sendMessage(msg2);// 即时send
        myHandler.sendEmptyMessageAtTime(1, uptimeMillis);// 在uptimeMillis时间点,send属性what值为1的Message
        myHandler.sendEmptyMessage(1);// send属性what值为1的Message
        //其他以此类推

DEMO1

在Activity中,定义一个Button,TextView,我们点击Button来实时的更新这个TextView的内容。

package com.dimos.handler;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    private TextView textView;
    private MyHandler myHandler;// 定义一个自己的Handle类
    private Button button;
    private MyThread m = new MyThread(); // 定义一个自己的线程类

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.txtShow);
        button = (Button) findViewById(R.id.btnOnlick);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                myHandler = new MyHandler();
                new Thread(m).start();
                System.out.println("主线程运行ID:" + Thread.currentThread().getId());
            }
        });
    }// 在对UI进行更新时,执行时所在的线程为主UI线程

    class MyHandler extends Handler {// 继承Handler类时,必须重写handleMessage方法
        public MyHandler() {
        }

        public MyHandler(Looper looper) {
            super(looper);
        }



        @Override
        public void handleMessage(Message msg) {// 执行接收到的通知,此时执行的顺序是按照队列进行,即先进先出
            super.handleMessage(msg);
            Bundle b = msg.getData();
            String textStr1 = b.getString("textStr");
            textView.setText(textStr1);// 更改TextView中的值
        }
    }// 该线程将会在单独的线程中运行

    class MyThread implements Runnable {
        int i = 1;

        @Override
        public void run() {
            while (i < 11) {
                System.out.println("当前运行线程ID:" + Thread.currentThread().getId());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message msg = new Message();
                Bundle b = new Bundle();
                b.putString("textStr", "线程运行" + i + "次");
                i++;
                msg.setData(b);
                myHandler.sendMessage(msg);// 通过sendMessage向Handler发送更新UI的消息
            }
            i = 1;// 下次启动线程时重新计数。
        }
    }
}

XML文件 activity_main.xml如下:

<RelativeLayout 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" >
    
    <Button 
        android:id="@+id/btnOnlick"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:text="点击"/>

    <TextView
        android:id="@+id/txtShow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="被点前"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"/>

</RelativeLayout>

可以看到,屏幕上的TextView在实时变化,考察线程ID可以得知是由哪一个线程来完成这项工作的。再次点击按钮后,则会触发新的线程去执行实时更新的操作。

二、发送和处理消息 Runnable

Runnable runnable = new Runnable() {

            @Override
            public void run() {
                
            }
        };
        long time = System.currentTimeMillis();
        myHandler.post(runnable);// 即使post
        myHandler.postAtFrontOfQueue(runnable);// 插入队头
        myHandler.postAtTime(runnable, time);// 在time时间点 post
        myHandler.postDelayed(runnable, 3000);// 延迟3秒 post
        // 其他以此类推

DEMO2

package com.dimos.handler;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;

public class HandlerMsg extends Activity {

    private Handler handler = new Handler();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        handler.post(new MyRunnable());
        System.out.println("Oncreate---The Thread id is :"
                + Thread.currentThread().getId());
        setContentView(R.layout.activity_main);
    }

    private class MyRunnable implements Runnable {
        public void run() {
            System.out.println("Runnable---The Thread is running");
            System.out.println("Runnable---The Thread id is :"
                    + Thread.currentThread().getId());
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }
}

控制台的输出结果:

: Oncreate---The Thread id is :1
: Runnable---The Thread is running
: Runnable---The Thread id is :1

程序启动后6秒,我们才看到activity_main.xml中的内容(只是显示一个TextView)。

这表明handler和主线程是同一个线程。如果这时候你做的是一个耗时的操作(比如下载),那么这样是不可行的。

android给我们提供了Looper这样一个类。其实Android中每一个Thread都跟着一个Looper,Looper可以帮助Thread维护一个消息队列。

DEMO3

package com.dimos.handler;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;

public class HandlerMsg2 extends Activity {

    private Handler handler = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        HandlerThread handlerThread = new HandlerThread("myHandlerThread");
        handlerThread.start();

        handler = new Handler(handlerThread.getLooper());

        handler.post(new MyRunnable());

        System.out.println("Oncreate---The Thread id is :"
                + Thread.currentThread().getId());

        setContentView(R.layout.activity_main);

    }

    private class MyRunnable implements Runnable {

        public void run() {
            System.out.println("Runnable---The Thread is running");
            System.out.println("Runnable---The Thread id is :"
                    + Thread.currentThread().getId());
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }
}

输出结果:

: Oncreate---The Thread id is :1
: Runnable---The Thread is running
: Runnable---The Thread id is :2833

程序启动后,我们立刻看到activity_main.xml中的内容,这样就达到了多线程的结果。

 

其实handler.post(Runnable)很强大,在很多地方都有用到,如

Gallery的onItemClick 跟onTouchEvent 不能同时用在3.0之后,但是可以用handler.post(Runnable)解决:

Create Handler作为一个全局变量

private Handler handler;

onCreate中new Handler,所以handler在主线程

handler = new Handler();

然后在Gallery的onItemClick里面用handler.post(Runnable),like this

handler.post(new Runnable() {
            
            @Override
            public void run() {
                // Do what ever...
            }
        });

 

posted @ 2013-07-06 14:42  百里抱木  阅读(574)  评论(2编辑  收藏  举报