一.什么是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对象。

图解:


Handler深度理解

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


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


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


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


仔细观察: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(安卓)线程间通信机制(ITC详解)
  2. Looper
  3. 解决Only the original thread that created a view hierarchy c
  4. Android之在子线程更新UI(超详细)
  5. Android聊天室(服务器)
  6. Android之——多线程断点续传下载示例
  7. Handle详解和使用方法
  8. Android简明开发教程十九:线程 Bezier曲线
  9. android中简单的Handler与Message

随机推荐

  1. 用户管理加登录验证、注册、管理权限
  2. Ajax数据异步加载、无刷新分页、编辑与删
  3. 从数组中移除元素,要求时间复杂度为O(N)空
  4. xxl-job源码分析与架构介绍
  5. 用Python关于 文件的复制移动压缩解压
  6. 多文件上传、MVC依赖注入与服务容器
  7. PHP 入门之一(写到哪、数据类型)
  8. PHP多文件上传案和MVC简单案例以及MVC的
  9. js事件与常用函数
  10. CISSP学习:第12章安全通信与网络攻-击