Android Handler的使用

一、Handler的定义:
主要接受子线程发送的数据, 并用此数据配合主线程更新UI.
解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发, 比如说, 你要是点击一个 Button, Android会分发事件到Button上,来响应你的操作。  如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示  “强制关闭”.  这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的. 这个时候,Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据)  , 把这些消息放入主线程队列中,配合主线程进行更新UI。

二、Handler一些特点
handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),
它有两个作用: (1):  安排消息或Runnable 在某个主线程中某个地方执行, (2)安排一个动作在不同的线程中执行
Handler中分发消息的一些方法
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
以上post类方法允许你排列一个Runnable对象到主线程队列中,
sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新.

三、下面我们来看一个简单的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class StartButtonListener implements OnClickListener{

  public void onClick(View v){
    handler.post(updateThread);
  }
}

class EndButtonListener implements OnClickListener{

  public void onClick(View v){
    handler.removeCallbacks(updateThread);
  }
}

Handler handler = new Handler();

Runnable updateThread = new Runnable(){

  public void run(){
    System.out.println("UpdateThread");
    handler.postDelayed(updateThread, 3000);
  }
};

以上一个start按钮和一个end按钮分别绑定post和remove方法。当我们点击start按钮时,updateThread会被加入到消息队列中,然后执行里面的run方法,打印出UpdateThread,然后设置延迟3000毫秒再把updateThread重新加入消息队列,所以我们在控制台看到的是每隔3秒打印出UpdateThread,直到我们点击end按钮,removeCallbacks。

image

我们再来看另一个例子(通过Handler来更新进度条的状态):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//当点击startButton按钮时,就会执行ButtonListener的onClick方法
    class ButtonListener implements OnClickListener{

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            bar.setVisibility(View.VISIBLE);
            updateBarHandler.post(updateThread);
        }
       
    }
    class stopButtonListener implements OnClickListener{

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            updateBarHandler.removeCallbacks(updateThread);
        }
       
    }
    //使用匿名内部类来复写Handler当中的handleMessage方法
    Handler updateBarHandler = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            bar.setProgress(msg.arg1);
            Bundle bundle = msg.getData();
            updateBarHandler.post(updateThread);
            System.out.println("test---->" + bundle.getString("test"));
        }
       
    };
    //线程类,该类使用匿名内部类的方式进行声明
    Runnable updateThread = new Runnable(){
        int i = 0 ;
        @Override
        public void run() {
            System.out.println("Begin Thread" + i);
            i = i + 10 ;
            //得到一个消息对象,Message类是有Android操作系统提供
            Message msg = updateBarHandler.obtainMessage();
           
            //将msg对象的arg1参数的值设置为i,用arg1和arg2这两个成员变量传递消息,优点是系统性能消耗较少
            msg.arg1 = i ;
            Bundle bundle = new Bundle();
            bundle.putString("test", "test bundle");
            msg.setData(bundle);
            try {
                //设置当前显示睡眠1秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //将msg对象加入到消息队列当中
            if( i > 100){
                //如果当i的值为100时,就将线程对象从handler当中移除
                updateBarHandler.removeCallbacks(updateThread);
                System.out.println(">>>>>>");
            }else{
                updateBarHandler.sendMessage(msg);
                System.out.println("<<<<<<");
            }
        }
    };

运行效果是每隔一秒自动更新进度条的状态。

四、Handler与主线程之间的关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class HandlerTest extends Activity {
    private Handler handler = new Handler();
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        handler.post(r);
        setContentView(R.layout.main);
        System.out.println("activity--->" + Thread.currentThread().getId());
        System.out.println("activityname--->" + Thread.currentThread().getName());
    }
   
   
    Thread r = new Thread(){
        @Override
        public void start(){
            System.out.println("start---------");
            super.start();
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            System.out.println("handler--->" + Thread.currentThread().getId());
            System.out.println("handlername--->" + Thread.currentThread().getName());
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
       
    };

}

打印结果:

image

通过上面我们可以看出来,Handler和Activity是处于同一线程中,如果程序在设计的时候需要线程初始化较长时间或者下载文件,这种情况下,主线程是出于等待状态的,甚至出现假死现象。

解决办法是是用HandlerThread类来创建独立于主线程的新线程,实现异步机制,不会影响到主线程的运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class HandlerTest2 extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //打印了当前线程的ID
        System.out.println("Activity-->" + Thread.currentThread().getId());
        //生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,这个类由Android应用程序框架提供
        HandlerThread handlerThread = new HandlerThread("handler_thread");
        //在使用HandlerThread的getLooper()方法之前,必须先调用该类的start();
        handlerThread.start();
        MyHandler myHandler = new MyHandler(handlerThread.getLooper());
        Message msg = myHandler.obtainMessage();
        //将msg发送到目标对象,所谓的目标对象,就是生成该msg对象的handler对象
        Bundle b = new Bundle();
        b.putInt("age", 20);
        b.putString("name", "Jhon");
        msg.setData(b);
        msg.sendToTarget();
    }
   
    class MyHandler extends Handler{
        public MyHandler(){
           
        }
        public MyHandler(Looper looper){
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            Bundle b = msg.getData();
            int age = b.getInt("age");
            String name = b.getString("name");
            System.out.println("age is " + age + ", name is" + name);
            System.out.println("Handler--->" + Thread.currentThread().getId());
            System.out.println("handlerMessage");
        }
    }
}

打印结果:

image

从上面我们可以看出我们处理消息的Handler并不在Activity的线程中,这才是真正的显示异步线程处理。

我们可以通过message的arg、obj、data来传递参数。

 

 

除非注明,Coder文章均为原创,转载请以链接形式标明本文地址

本文地址:http://www.alonemonkey.com/android-handler.html

本文链接:http://www.alonemonkey.com/android-handler.html