理解Android的handler机制--从应用到原理再到实践

关于Android的多线程机制,面试的时候总是问到,今天专门写这个博客,目的是把handler说清楚。

分别从下面四个方向说清楚。

 

由来

问题:为什么有handler?

我们知道java是支持多线程的,而一个APP只有一个UI(即屏幕只有一个),如果每个线程都可以更新UI,呵呵,估计我们的APP就乱套了,所以Android的设计者就想着,更新UI只能在主线程中,子线程是不能更新UI的,子线程如果更新UI,系统就会抛出异常。所以Android就需要提供一种机制,子线程通过这种机制可以在主线程中更新UI。

那么java有没有提供在子线程之间实时通讯的机制??? 由于线程的特性,一个进程内的所有线程够共享同一存储空间,即在多线程中,线程是可以访问同一内存单元,这样很可能出现数据不同步的问题,因此java提供了 synchronized关键字 和 Object 类的wait和notify方法(当然java还提供别的方法),但是此方法对Android更新UI这种特殊场合不是很适用。

因此Android专门提供了异步消息处理机制,用来解决在Android子线程中更新UI的操作。即handler机制。

应用

handler机制是为了在子线程中更新UI的,但是handler的作用不仅仅是为了更新UI的,准确的说是为了异步消息处理,因此从以下三种情况说明消息是如何发送和接受的。

子线程向主线程发送消息

Android是基于Java的,所以也分主线程,子线程!

(1)主线程:实现业务逻辑、UI绘制更新、各子线程串连,类似于将军; 

(2)子线程:完成耗时(联网取数据、SD卡数据加载、后台长时间运行)操作,类似于小兵; 

对于使用者来说,代码默认执行在主线程中,子线程的代码在new thread内执行的代码。

第一步:在主线程中创建一个handler

    private Handler handler = new Handler() {

        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATE_TEXT:
                    // 在这里可以进行UI操作
                    text.setText("Nice to meet you");
                    break;
                default:
                    break;
            }
        }

    };

第二步:开启一个子线程,在子线程里直接使用Handler发送消息即可

new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message message = new Message();
                        message.what = UPDATE_TEXT;
                        handler.sendMessage(message); // 将Message对象发送出去
                    }
                }).start();

主线程向子线程发送消息

分两种情况:

方法1在子线程里初始化Looper

主线程向子线程发送消息的话,我们需要在子线程里初始化Looper,并在主线程里创建的Handler引用子线程的Looper(Handler中引用的是哪个线程的Looper,就在哪个线程里处理消息),下面看代码:

    //方法1
    public void method1(){
        thread = new MyThread();
        thread.start();//千万别忘记开启这个线程

        delay(1000);  //在Handler初始化的时候,thread.looper还没有初始化,所以加一个延时

        handler1 = new Handler(thread.looper){
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case UPDATE:
                        // 在这里可以进行UI操作
                        Log.d("当前子线程是--1--->",Thread.currentThread()+"");
                        break;
                    default:
                        break;
                }
            };
        };
    }


    //子线程
    class MyThread extends Thread{
        private Looper looper;//取出该子线程的Looper
        public void run() {
            Looper.prepare();//创建该子线程的Looper
            looper = Looper.myLooper();//取出该子线程的Looper
            Looper.loop();//只要调用了该方法才能不断循环取出消息
        }
    }

主线程发送消息:

//下面是主线程发送消息
Message message1 = new Message();
message1.what = UPDATE;
handler1.sendMessage(message1);
break;

这种方法有个确定,就是Handler初始化的时候,thread.looper还没有初始化,会导致Crash。

方法2使用HandlerThread

Android提供了HandlerThread类,子线程中有handler,代码如下:

    //方法2
    public void method2(){
        //实例化一个特殊的线程HandlerThread,必须给其指定一个名字
        HandlerThread thread = new HandlerThread("handler thread");
        thread.start();//千万不要忘记开启这个线程
        //将mHandler与thread相关联
        handler2 = new Handler(thread.getLooper()){
            public void handleMessage(android.os.Message msg) {
                switch (msg.what) {
                    case UPDATE:
                        // 在这里可以进行UI操作
                        Log.d("当前子线程是--2--->",Thread.currentThread()+"");
                        break;
                    default:
                        break;
                }
            };
        };
    }

子线程向子线程发送消息

创建子线程,该子线程接受并处理消息,(注意,该子线程的创建也可以应用上面的情况)

new Thread(new Runnable() {
	@Override
	public void run() {
		Looper.prepare();
		childHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				super.handleMessage(msg);
				switch (msg.what) {
					case SEND:
						// 在这里可以进行UI操作
						Log.d(TAG,"这个消息是从-->>" + msg.obj + "过来的,在" + Thread.currentThread()+ "子线程当中执行的");
						break;
					default:
						break;
				}
			}

		};
		Looper.loop();//开始轮循
	}
}).start();

发送消息线程:

new Thread(new Runnable() {
	@Override
	public void run() {
		Message msg = childHandler.obtainMessage();
		msg.what = SEND;
		msg.obj =  ""+ Thread.currentThread();
		childHandler.sendMessage(msg);
	}
}).start();

以上分析主要参考Android使用Handler实现子线程与子线程、主线程之间通信,但是这偏文章没有写好的源代码,在总结这篇文章的基础上,实现代码并上传github,可直接下载运行。

原理

原理分析,主要查看郭霖的《第一行代码,第二版》。

java实现

理解了handler机制后,我们可不可以用java手写一个handler机制呢?

猜你喜欢

转载自blog.csdn.net/gs344937933/article/details/83096029