AndroidAndroid技术知识Android知识

Handler消息机制

2017-07-31  本文已影响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与之关联。

过程:先调用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内部会对其进行管理,这样我们就只需要关注于我们的业务逻辑即可。

上一篇 下一篇

猜你喜欢

热点阅读