Handler消息机制

作者: 我想成为创业者 | 来源:发表于2017-07-31 15:13 被阅读69次

    一. 为什么使用Handler

    1. 当UI线程出现耗时操作时会ANR(Application Not Responding),为了避免ANR,通常把耗时操作放在子线程里面去执行,但是子线程不能更新UI,当子线程需要更新UI的时候就需要借助Android消息机制,也就是Handler机制。

    如果在子线程中做更新UI的操作会出现android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

    1. Handler还用于处理延时任务

    二. Handler消息机制原理

    Handler不是独立存在的,一个handler一定有一个专属的线程,一个消息队列(MessageQueue),和一个looper与之关联。

    • Handler——既是发送者也是接收处理者
    • MessageQueue——Handler发送的消息Message需要一个容器来存放消息,MessageQueue就是这个消息队列。
    • Looper——Message被Handler发送出来,会被放入MessageQueue中,放入其中的Message在条件成熟的时候会被取出来,交由Handler去处理。整个过程中还需要一个对象来执行从MessageQueue取出并交给对应Handler的工作,Looper就是这个对象

    过程:先调用Looper.prepare()创建Looper,然后执行你的代码,最后调用Looper.loop()执行死循环。注意Looper.loop()一定放到代码的最后一行。死循环中会执行MessageQueue.next()方法去取出队列中的消息,当消息为空时,MessageQueue.next()方法中会执行nativePollOnce()native方法休眠Looper.loop()死循环。当有新的消息插入到MessageQueue中,也就是调用MessageQueue.enqueueMessage()方法,这个方法当中会判断Looper是否是休眠状态,如果是休眠状态会执行nativeWeak()native方法来唤醒Looper()

    注意:
    1.创建之前必须先初始化Looper,否则会RuntimeException(在主线程中初始化Handler对象前,系统默认通过Looper对象调用了一次prepare方法)
    2.在Looper.prepare()的同时,Looper.loop()来启动循环,否则Handler仍然无法正常接收;
    3.因为Looper.loop()有死循环,Looper.loop()之后的代码将无法执行,所以需要将Looper.loop()放在代码最后;
    4.Looper在每个线程只能存在一个,如果再去手动创建Looper也会抛出RuntimeException;

    三. Handler的使用

    1. Thread+Handler
    • 发送空
    private void sendEmpty() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    handler.sendEmptyMessage(EMPTY);
                }
            }).start();
        }
    
    • 发送非空
        private void sendUnEmpty() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Message msg = handler.obtainMessage();
                    msg.what = UNEMPTY;
                    Bundle data = new Bundle();
                    data.putString("send1", "白夜行");
                    msg.setData(data);
                    handler.sendMessage(msg);
                }
            }).start();
        }
    
    • 接收
        private static final int EMPTY = 1;
        private static final int UNEMPTY = 2;
        private Handler handler=new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if(msg.what== EMPTY){
                    sendEmpty.setText("EMPTY");
                }  else if(msg.what== UNEMPTY){
                    Bundle data = msg.getData();
                    sendUnempty.setText(data.getString("send1"));
                }
            }
        };
    
    1. Runnable + Handler.post
       new Thread() {
                @Override
                public void run() {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            //更新界面
                        }
                    });
                }
            }.start();
    
    1. TimerTask + Handler——无限循环使用Java自带的TimerTask类,TimerTask相对Thread来说资源消耗更低
    private Timer timer = new Timer();
     private void goLooper() {
       timer.schedule(new TimerTask() {
        @Override
        public void run() {
         handler.sendEmptyMessage(0);
        } }, 0, 1000);
    }
    //取消timer.cancel(); 
    
    1. 子线程使用Handler
        private void createThreadHandler() {
            new Thread() {
                public void run() {
                    Looper.prepare();
                    threadHandler = new Handler() {
                        public void handleMessage(android.os.Message msg) {
                            if (msg.what == 0) {
                                Toast.makeText(HandlerActivity.this, "子线程Handler", Toast.LENGTH_SHORT).show();
                            }
                        }
                    };
                    Looper.loop();
                }
            }.start();
        }
    
    private void useThreadHandler() {
            if (threadHandler != null) {
                new Thread() {
                    public void run() {
                        threadHandler.sendEmptyMessage(0);
                    }
                }.start();
            }
        }
    

    附加:
    AsyncTask是android提供的一个助手类,它对Thread和Handler进行了封装,方便我们使用。Android之所以提供AsyncTask这个类,就是为了方便我们在后台线程中执行操作,然后将结果发送给主线程,从而在主线程中进行UI更新等操作。在使用AsyncTask时,我们无需关注Thread和Handler,AsyncTask内部会对其进行管理,这样我们就只需要关注于我们的业务逻辑即可。

    相关文章

      网友评论

        本文标题:Handler消息机制

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