关于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(){        MyThread thread = new MyThread();        thread.start();//千万别忘记开启这个线程//        delay(1000);  //在Handler初始化的时候,thread.looper还没有初始化,所以加一个延时        // 或者使用 wait() 方法。        synchronized (thread) {            if(thread.looper == null) {                try{                    thread.wait();                }catch (Exception e){                    e.printStackTrace();                }            }        }        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            // 使用 notify() 方法唤醒。            synchronized (this) {                this.notify();            }            Looper.loop();//只要调用了该方法才能不断循环取出消息        }    }

主线程发送消息:

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

这种方法有个问题,就是Handler初始化的时候,thread.looper还没有初始化,会导致Crash,上面的代码中加了一个延时解决问题了,或者使用 wait()和notify()方法解决,但有更好的解决办法,就是使用HandlerThread。

方法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() {@Overridepublic void run() {Looper.prepare();childHandler = new Handler() {@Overridepublic 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() {@Overridepublic void run() {Message msg = childHandler.obtainMessage();msg.what = SEND;msg.obj =  ""+ Thread.currentThread();childHandler.sendMessage(msg);}}).start();

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

 

原理

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

 

(1)ActivityThread.main() 函数中,调用 Looper.prepareMainLooper();
(2)Looper.prepareMainLooper(); 的作用是初始化当前线程作为一个主线程。具体内容是,创建一个Looper对象,并将该对象赋值给sThreadLocal变量。
(2.1)在创建Looper对象的时候,其构造函数会创建MessageQueue对象。
(3)最后,ActivityThread.main() 会调用Looper.loop(); 函数。
(4)而Looper.loop();函数会从队列中取出message,并调用Handler. dispatchMessage()函数。

从上面可以看出,其关键是Looper对象。

 

java实现

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

 

 

 

 

 

更多相关文章

  1. Android开发:Handler异步通信机制全面解析(包含Looper、Message Qu
  2. Effective Java读书笔记、感悟——1.创建和销毁对象
  3. 如何检测 Android(安卓)Cursor 泄漏
  4. FastJson的基本使用
  5. Android(安卓)Handler主线程和一般线程通信的应用分析
  6. Android(安卓)UI 卡顿及ANR检测原理
  7. 你真的懂Android(安卓)Handler吗?(一)
  8. android应用程序线程的监控
  9. Android9.0应用弹窗“此应用专为旧版Android打造,因此可能无法正

随机推荐

  1. Android Studio 构建那些事
  2. Android(安卓)关于lambda 的下划线
  3. webView系列(十一)----webview网页调试之se
  4. Android热修复:Andfix和Hotfix,两种方案的
  5. 【边做项目边学Android】异常处理:android
  6. Windows7 64位系统搭建Cocos2d-x-2.2.1最
  7. 【Android】技术调研:用代码模拟屏幕点击
  8. Android软件安全开发实践(上)
  9. [转]android开发新浪微博客户端 完整攻略
  10. Android Launcher开发(一)LiveFolder(实