Android的Handler总结

(1)Handler的定义

        当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) ,主线程管理界面中的UI控件。如果此时需要一个耗时的操作,例如联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中。如果你放在主线程中的话,UI界面会出现假死现象,如果5秒钟还没有完成的话,会收到Android系统的一个错误提示  "强制关闭"。

         这个时候我们需要把这些耗时的操作,放在其它线程中。 这个时候Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这些消息会被子线程发往主线程队列中,配合主线程进行更新UI。

(2)Handler一些特点
        每个Handler实例,都会绑定到创建它的线程中(一般是主线程)。它有两个作用:a, 发送消息;b,安排Runnable 。
安排Runnable的一些方法:
        post(Runnable)
        postAtTime(Runnable,long)
        postDelayed(Runnable, long)

发送消息的一些方法:
        sendEmptyMessage(what)
        sendMessage(Message)
        sendMessageAtTime(Message,long)
        sendMessageDelayed(Message,long)
以上post类方法允许你排列一个Runnable对象到主线程队列中,sendMessage类方法允许你发送一个带数据的Message对象到队列中,等待更新。

(3)消息机制的几个常见名词概念
A,Handler:消息的封装者和处理者,handler负责将需要传递的信息封装成Message,将消息传递给Looper,继而由Looper将Message放入MessageQueue中。当Looper对象看到MessageQueue中含有Message,就将其广播出去。该handler对象收到该消息后,调用相应的handler对象的handleMessage()方法对其进行处理。
  B,Message:消息对象,Message Queue中的存放的对象。一个Message Queue中包含多个Message。Message实例对象的取得,通常使用Message类里的静态方法obtain(),该方法有多个重载版本可供选择;调用removeMessages()时,将Message从Message Queue中删除。
C,MessageQueue:就是一个消息队列,存放消息的地方。每一个线程最多只可以拥有一个MessageQueue数据结构。创建一个线程的时候,并不会自动创建其MessageQueue。通常使用一个Looper对象对该线程的MessageQueue进行管理。主线程创建时,会创建一个默认的Looper对象,而Looper对象的创建,将自动创建一个Message Queue。其他非主线程,不会自动创建Looper,要需要的时候,通过调用prepare函数来实现,和Looper.loop()。
D,Looper:是MessageQueue的管理者。每一个MessageQueue都不能脱离Looper而存在,Looper对象的创建是通过prepare函数来实现的。同时每一个Looper对象和一个线程关联。通过调用Looper.myLooper()可以获得当前线程的Looper对象,创建一个Looper对象时,会同时创建一个MessageQueue对象。除了主线程有默认的Looper,其他线程默认是没有MessageQueue对象的,所以,不能接受Message。如需要接受,自己定义一个Looper对象(通过prepare函数),这样该线程就有了自己的Looper对象和MessageQueue数据结构了。Looper从MessageQueue中取出Message然后,交由Handler的handleMessage进行处理。

(4)Handler实例

     以下为一个实例,它实现的功能为通过线程修改Button的内容,即子线程发消息给主线程

public class MainActivity extends Activity {
    Button button;
    MyHandler myHandler;
    public static final String Tag = "handler";
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.button1);       
        myHandler = new MyHandler();  
        myHandler.postDelayed(myRunnable, 1000);
    }
    
    class MyHandler extends Handler {  
        public MyHandler() {  
        }  
  
        public MyHandler(Looper L) {  
            super(L);  
        }  
  
        // <strong>子类必须重写此方法,接受数据 </strong> 
        @Override  
        public void handleMessage(Message msg) {  
            // TODO Auto-generated method stub  
            Log.d("MyHandler", "handleMessage......");  
            super.handleMessage(msg);  
            // 此处可以更新UI  
            Bundle b = msg.getData();  
            String color = b.getString("color");  
            MainActivity.this.button.append(color);  
        }  
    }  

    private Runnable myRunnable= new Runnable() {
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Message msg = new Message();
            Bundle b = new Bundle();// 存放数据
            b.putString("color", "我的");
            msg.setData(b);

           	myHandler.sendMessage(msg); // 向Handler发送消息,更新UI
        }
    };
 }

除上述用法之外,主线程给主线程自己发消息、主线程给子线程发消息、子线程给子线程自己发消息,样例都可以参见http://blog.csdn.net/aaa2832/article/details/7773220#comments,

(5)为什么不能再子线程中更新UI,仅能发出消息

     如果在子线程中直接更新UI,通常会抛出下面的异常:
        11-07 13:33:04.393: ERROR/JavaBinder(1029):android.view.ViewRoot$CalledFromWrongThreadException:Only the original thread that created a view hierarchy can touch its views.意思是,无法在子线程中更新UI。

(6)Handler用定时器执行重复刷UI的操作

         需要引入import java.util.Timer; 和 import java.util.TimerTask;首先Timer用来定时执行某个TimerTask, TimerTask仅仅用Handler来发出刷界面的消息,而不是去刷界面,刷界面的操作由handleMessage来完成就行了。

public class TestTimer extends Activity {    
    Timer timer = new Timer();  
    Handler handler = new Handler(){   
        public void handleMessage(Message msg) {  
            switch (msg.what) {      
            case 1:      
                setTitle("hear me?");  
                break;      
            }      
            super.handleMessage(msg);  
        }            
    };  

    TimerTask task = new TimerTask(){    
        public void run() {  
            Message message = new Message();      
            message.what = 1;      
            handler.sendMessage(message);    
        }            
    };  

    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);   
        timer.schedule(task, 10000);  
    }  
}
(7)Handler用于设置某个时间点执行某个操作。         Runnable + Handler.postDelayed(runnable,time),DEMO如下:
    private Handler handler = new Handler();  
  
    private Runnable myRunnable= new Runnable() {    
        public void run() {             
            if (run) {  
                handler.postDelayed(this, 1000);  
                count++;  
            }  
            tvCounter.setText("Count: " + count);  
        }  
    };
postDelayed的结果指向自己,也可以完成重复的操作

(8)如何在service中调用activity中的handler

在service中定义一个handler,然后定义一个void sethandler(Handler handler )把activity的handler传过来,在service中sendmessage,activity中就可以接收了



参考原文:http://www.cnblogs.com/devinzhang/archive/2011/12/30/2306980.html

参考原文:http://www.cnblogs.com/dawei/archive/2011/04/09/2010259.html

参考原文:http://bbs.csdn.net/topics/370191134

参考原文:http://blog.csdn.net/chenqiumiao/article/details/7652745

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值