一.什么是Handler

    Handler是Android给我们提供用来更新UI的一套机制,是一套消息处理机制,可以通过它来发送消息和处理消息。那作为开发者的我们,不禁会疑问?Google为什么要设计这套机制呢?这是为了解决在非UI线程中更新UI组件比较麻烦的问题。那么Android为什么不能在非UI线程中更新呢?首先Android的UI控件不是线程安全的,这是因为避免多线程并发所带来不安全问题。例如作一个假设,现在在子线程中刷新界面,同时也在UI线程中刷新界面,就会出现刷新不同步,简单来讲通过Handler就可以更新UI操作切换到主线程中执行。

二.Handler机制

 Handler机制主要角色

Message:消息,就是一个载体,包含消息ID,消息处理对象和处理的数据等,统一放到MessageQueue,最终由Handler处理。

Handler:用于同一个进程的线程间通信,消息处理者,专门负责Message的发送和处理。我们使用Handler时,一般通过handleMessage(Message msg)来处理Message,也就是统一处理消息的回调,确保自己发出的消息也是自己来处理。

MessageQueue:由名字可推出这是队列,就是存放Handler发送过来的消息,按照先进先出的顺序规则来执行。将链表的数据结构以Message来串联起来,等待Looper的抽取,为什么需要队列呢?因为同一线程在一个时间只能处理一个消息。因此需要队列来保存这些消息,然后挨个挨个拿出来处理,创建一个线程时并不会自动创建MessageQueue,但是主线程创建时会默认创建Looper对象,而Looper创建时就会创建MessageQueue,其他非主线程需要looper的时候就会通过调用prepare函数来实现。

Looper:首先要理解一个线程是一段可执行的代码,作为App的主线程,不能让代码执行完,因为代码执行完的话app就会自动退出,因此不能让主线程不能让代码段执行,只能在代码中插入一个死循环,这时候Looper的作用就体现出来了,将主线程变成Looper线程。并且这时主线程就会在等其他线程发消息(更新UI和Activity状态等等)那,另外,Looper不断从消息队列拿出消息给主线程,也就是无限循环去查找是否有消息,有就去处理,没有的话就一直等待,一个MessageQueue需要一个Looper。

Thread:负责调度整个消息的循环。

通过上面可以得知:Handler的作用是发送和处理消息,Handler发送的消息必须被送到指定MessageQueue中,也就是说,要让Handler正常工作就必须有一个MessageQueue,但是MessageQueue是由Looper来抽取自身的Message,也因此当前线程中必须有一个Looper对象。

图解:

Android之Handle全面理解_第1张图片

Handler深度理解

根据上面可得:每一个线程都必须有Looper,但是我们不禁会有疑问?主线程我们并没有创建Looper?其实主线程是ActivityThread,ActivityThread被创建的时候就会初始化Looper。

Android之Handle全面理解_第2张图片

上面红色箭头就是主线程创建Looper对象代码语句。那么我们继续进入Looper去看看究竟是什么操作。

Android之Handle全面理解_第3张图片

果然上面所分析的几个主要角色都在:Looper,MessageQueue,Thread,但是还多了一个ThreadLocal,这个是什么呢?其实这个是一个线程内部的数据存储类,通过它可以在指定线程中存储数据,数据存储以后,只有在指定的线程获取到存储数据,对于其他线程来说则无法获取到数据,后面例子再详细叙述。

Android之Handle全面理解_第4张图片

这时候又有疑问,为什么主线程中有一个死循环,但是没有造成阻塞呢?那我们从ActivityThread类开始分析:这个并不是一个真正的线程,就只是一个类,从main方法看到有Looper,那找找其对应的Handler,ActivityThread有一个内部类,继承Handler,并找到handleMessage

Android之Handle全面理解_第5张图片

仔细观察:Activity的生命周期都有对应的case条件,并且service的生命周期等等都有条件。也就是通过loop来分发消息内部类的Handler,就会进入handleMessage。就会根据对应的条件来执行对应的代码,不断执行传递过来的消息。那么可以总结来说:ActivityThread的main方法主要是来做消息循环的,如果消息循环退出了,那么程序就退出了。但是从队列里取出消息可能会造成阻塞,如果某个消息处理的时间过于长,那么会影响UI线程的刷新,就造成卡顿现象。不会造成卡在的真正原因主要有二:

1.当没有消息来的时候就会wait,有句柄写的时候就会唤醒,进行等待。

2.所有的UI更新操作都通过handler来发消息。如各种的点击事件都会造成句柄写的操作来唤醒等待。

主线程是UI线程,优先级很高,主线程的死循环会不会特别消耗CPU资源呢?

其实如果主线程的队列里没有消息时,就会阻塞在loop的queue.next()里,这时候主线程就会释放CPU资源进入休眠状态,直到下个消息进来时就会唤醒主线程,现在是通过pipe管道来写入数据,类似I/0,不占用资源。

三.例子实践

下面简单写一个小例子加深理解:

倒计时例子:

public class MainActivity extends Activity {    private TextView text_one;    private mHandler mhandler = new mHandler(this);    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        text_one = findViewById(R.id.text_one);        start();    }    //Handler静态内部类 防止内存泄漏    private static class mHandler extends Handler{       WeakReference weakReference;       public mHandler(MainActivity mainActivity){           weakReference = new WeakReference(mainActivity);       }       @Override        public void handleMessage(Message msg){           MainActivity mainActivity = weakReference.get();           if(mainActivity != null){                 mainActivity.text_one.setText(String.valueOf(msg.arg1));           }       }    }  private void start(){         new Thread(new Runnable() {             @Override             public void run() {                 for(int i = 10;i>0;i--){                     Message msg = new Message();                     msg.what = 01;                     msg.arg1 = i;                     mhandler.sendMessage(msg);                     try {                         Thread.sleep(1000);                     } catch (InterruptedException e) {                         e.printStackTrace();                     }                 }                 //计时结束后先不管            }         }).start();  }  @Override    protected void onDestroy(){      super.onDestroy();      if(mhandler != null){          mhandler.removeCallbacksAndMessages(null);      }  }

更多相关文章

  1. Android之在子线程更新UI(超详细)
  2. Android 线程间通信机制(ITC详解)
  3. android中使用线程池和临时缓存优化网络图片加载
  4. android的UI操作单线程模型理解
  5. android handler 多线程demo
  6. android JNI层线程回调Java函数

随机推荐

  1. Android中的国际化
  2. Android仿微信录制语音
  3. Android(安卓)Intent Activity 跳转几种
  4. Android的Bitmap处理大图片解决方法
  5. Android解析如何获取SDCard 内存
  6. Android(安卓)N进入分屏代码分析二
  7. Android(安卓)EventBus简单使用
  8. 图片常用的控件
  9. activity 设置Theme.Dialog View高度
  10. apk 反编译源码 资源文件