Handler

作者: 大灰狼zz | 来源:发表于2018-09-03 17:08 被阅读0次

    Handler机制详细解析请参考参考
    android中handler的一些总结以及使用(一)之handler的基本用法
    android中handler的一些总结以及使用(二)之handle使用时用到的几个主要方法介绍
    android中handler的一些总结以及使用(三)之HandleThread的使用

    Handler简介

    Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制,可以用来在多线程间进行通信,典型案例就是在另一个线程中更新UI界面。

    说到handler就不得不说Looper和MessageQueue,handler主要作用是发送消息(message)和处理消息,MessageQueue的作用是存储handler发送过来的Message,Looper顾名思义,就是不断地循环消息队列(MessageQueue),取出消息,交给handler执行。handler在初始化的时候会去绑定Looper,一个线程只能一个Looper,一个Looper中也只有一个MessageQueue,三者相互协同共同完成任务,缺一不可。

    handler的使用

    每次你新创建一个Handle对象,它会绑定于创建它的线程(也就是UI线程)以及该线程的消息队列,Handler可以把一个Message对象或者Runnable对象压入到消息队列中,进而在UI线程中获取Message或者执行Runnable对象,Handler把压入消息队列有两类方式

    handler的基本用法

    (1)主线程与子线程之间的通信

    public class HandlerTest extends AppCompatActivity {
     
        private static final String TAG = "HandlerTest";
        private Message mMessage;
     
        // new 一个handler实例,覆写 handleMessage()方法,用于处理消息
        private  Handler mHandle = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what){                  //根据msg.what区分是消息类型
                    case 0:
                        Log.d(TAG,"handleMessage of type 0");   // 根据不同消息类型,写出具体的处理方式
                    case 1:
                        Log.d(TAG,"handleMessage of type 1");
                }
            }
        };
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler_test);
            
            new Thread(new Runnable() {
                @Override
                public void run() {
     
                    // 首先需要创建message对象,有以下三种方式
                    // 1、 new Message()
                    mMessage = new Message();
     
                    // 2、调用Message类的静态方法 (推荐使用)
                    mMessage = Message.obtain();
     
                    // 3、调用handler类的方法(此方法是调用Message.obtain(Handler h)方法去创建Message对象)
                    mMessage = mHandle.obtainMessage();
                    
                    mMessage.what = 0;     // 不同的what值,用于区分不同的消息类型 
                    
                    // 发送消息到MessageQueue
                    mHandle.sendMessage(mMessage);
                }
            }).start();
        }
    }
    

    (2)子线程与子线程之间的通信

    前面说handler初始化时需要绑定Looper,上面的例子中我们并没有绑定写Looper,为什么也可以呢?
    是因为我们的应用在启动时,ActivityManager会去创建ActivityThread,用以维护Activity生命周期。ActivityThread中的main()方法应用的入口,在main()方法中,会去创建一个Looper对象,存储在线程的ThreadLocal对象中,handler在初始化时,会从ThreadLocal对象中去读取当前线程的Looper,所以才不需要我们手动去创建一个Looper。

    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler_test);
     
            final Thread Thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Looper.prepare();               // 创建一个Looper对象
                    mHandle = new Handler(){            
                        @Override
                        public void handleMessage(Message msg) {
                            super.handleMessage(msg);
                            Log.d(TAG,"handleMessage in Child Thread");
                        }
                    };
                    Looper.loop();                  // 开始循环消息队列
                }
            });
     
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Log.d(TAG,"enter send handleMessage");
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                    }
                    mHandle.sendEmptyMessageDelayed(1,5000);  
                }
            });
     
            Thread1.start();
            thread2.start();
        }
    }
    

    thread2发送消息到thread1中的handler,实现子线程与子线程间的通信。

    (3)handler发送消息的方法

    1、sendMessage      立即发送信息
    
    2、sendEmptyMessage    立即发送空消息
    
    3、sendMessageDelayed    指定延时多少毫秒后发送信息
    
    4、sendEmptyMessageDelayed        指定延时多少毫秒后发送空信息
    
    5、sendMessageAtTime    指定在什么时间发送消息
    
    6、sendEmptyMessageAtTime    指定在什么时间发送空消息
    
    7、post    立即发送信息
    
    8、postAtTime    指定在什么时间发送消息
    
    9、postDelayed     指定延时多少毫秒后发送信息
    

    以上9个方法实际上最终都是调用sendMessageAtTime方法,让我们看看两个典型的方法sendMessage和post

    sendMessage方法源码:

    public final boolean sendMessage(Message msg){
         return sendMessageDelayed(msg, 0); //调用sendMessageDelay方法
    }
    public final boolean sendMessageDelayed(Message msg, long delayMillis){
            if (delayMillis < 0) {
                delayMillis = 0;
            }
            return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  //调用sendMessageAtTime方法
     }
        
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            MessageQueue queue = mQueue;
            if (queue == null) {
                RuntimeException e = new RuntimeException(
                        this + " sendMessageAtTime() called with no mQueue");
                Log.w("Looper", e.getMessage(), e);
                return false;
            }
            return enqueueMessage(queue, msg, uptimeMillis);
     } 
    

    post方法源码:

    public final boolean post(Runnable r){
           return  sendMessageDelayed(getPostMessage(r), 0);  //最终也是调用sendMessageAtTime
        }
        
    private static Message getPostMessage(Runnable r) {
            Message m = Message.obtain();   //创建一个message对象,上一节讲message获取的几种方式时,我们也有提到过
            m.callback = r;    //将此Runable对象保存在message的callback变量上
            return m;
        }
    

    可以看出最后都是调用了sendMessageAtTime方法,最后再调用enqueueMessage

     private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;  //message的target属性保存着发送此消息的handler,建立了两者的对应关系
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);    //保存消息到队列中
        }
    

    handler发送消息后,该消息保存到消息队列中,上面我们提到过,loop方法会不断循环消息队列取出消息,然后交给目标handler(也就是message的target属性对应的handler,从这看一个队列是可以被多个handler共享的,但是一个handler只能绑定一个队列)处理。

    android 中更新UI的几种方式

    常见的大概有四种:runOnUiThread、handler.post、handler.sendMessage、view.post

    public class FiveActivity extends Activity {  
        // 只是在布局布置一个 TextView  
        private TextView textView;  
        // 通过Handler来更新一下UI  
        Handler handler = new Handler() {  
            // 实现一下Handler里面的handleMessage方法  
            public void handleMessage(android.os.Message msg) {  
                // 第二个方法是从外边拿到数据然后返回到里面  
                textView.setText("第二种方法handlerEmptyMessags");  
            }  
        };  
      
        /** 
         * 第一方法 Handler post 
         */  
        public void handler1() {  
            handler.post(new Runnable() {  
      
                @Override  
                public void run() {  
                    // 这里弄个文本消息  
                    textView.setText("第一种方法Handler post");  
      
                }  
            });  
        }  
      
        /** 
         * 第二种方法 sendEmptyMessage 
         */  
        public void handler2() {  
      
            handler.sendEmptyMessage(1);  
      
        }  
      
        /** 
         * 第三种方法 runOnUiThread 
         */  
        public void handler3() {  
            runOnUiThread(new Runnable() {  
      
                @Override  
                public void run() {  
      
                    textView.setText("第三个方方法runOnUiThread");  
                }  
            });  
        }  
      
        /** 
         * 第四种方法view 
         * post----它会判断当前是不是UI线程,默认情况下,会通过Handler.post发送一个action。如果是UI线程的话执行run()方法 
         */  
        public void handler4() {  
            textView.post(new Runnable() {  
      
                @Override  
                public void run() {  
      
                    textView.setText("第四种方法 view post");  
      
                }  
            });  
        }  
      
        protected void onCreate(Bundle savedInstanceState) {  
            // TODO Auto-generated method stub  
            super.onCreate(savedInstanceState);  
            // 将布局,引用到这个类---因为为了方便我弄多了一个类  
            setContentView(R.layout.five);  
            // 找到ID  
            textView = (TextView) findViewById(R.id.textview);  
            // 更新UI 创建一个线程,后台处理。  
            new Thread() {  
                // 实现线程Thread 中的run方法  
                public void run() {  
      
                    try {  
                        //休息两秒后再执行,因为本地网络速递较快,为了看效果。如果网络的话就去掉  
                        Thread.sleep(2000);  
      
                    //  handler1();  
                    //  handler2();  
                    //  handler3();  
                        handler4();  
      
                    } catch (InterruptedException e) {  
                        // TODO Auto-generated catch block  
                        e.printStackTrace();  
                    }  
      
                };  
            }.start();  
        }  
      
    }
    

    总结:常见的四种方式更新UI都差不多,都是通过Handler来更新,只是代码上的本质而已。

    在Android开发中,定时执行任务的3种实现方法

    相关文章

      网友评论

          本文标题:Handler

          本文链接:https://www.haomeiwen.com/subject/myobwftx.html