文档章节

android Handler机制详解

二进制的忧伤
 二进制的忧伤
发布于 2015/01/10 19:08
字数 1297
阅读 154
收藏 0

一、几个相关概念简述:

    1、MessageQueue:  消息队列,存放消息的容器。注意:每一个线程最多只有一个MessageQueue,创建一个线程的时候,并不会自动创建其MessageQueue。通常使用一个Looper对象对该线程的MessageQueue进行管理。主线程创建时,会创建一 个默认的Looper对象,而Looper对象的创建,将自动创建一个MessageQueue。其他非主线程,不会自动创建Looper,要需要的时候,通过调用prepare函数来实现。

    2、Message:消息对象,存储与MessageQueue中,一个MessageQueue包含多个Message对象,这些Message对象遵循先进先出的原则。注意:通常会new一个message实例对象,或者通过Handler对象的obtainMessage()获取一个Message实例,使用removeMessages()方法可以将消息从队列中删除;

    3、Looper:消息封装的载体,是MessageQueue的管理者。每一个MessageQueue都不能脱离Looper而存在,Looper对象的创建是通过prepare函数来实现的。同时每一个Looper对象和一个线程关联。通过调用Looper.myLooper()可以获得当前线程的Looper对象。注意:创建一个Looper对象时,会同时创建一个MessageQueue对象。除了主线程有默认的Looper,其他线程默认是没有MessageQueue对象的,所以,不能接受Message。如需要接受,自己定义一个Looper对象(通过prepare函数),这样该线程就有了自己的Looper对象和MessageQueue数据结构了。

    4、Handler:封装了消息的发送和处理,handler负责将需要传递的信息封装成Message,通过调用handler对象的obtainMessage()来实现; 将消息传递给Looper,这是通过handler对象的sendMessage()来实现的。继而由Looper将Message放入MessageQueue中。 当Looper对象看到MessageQueue中含有Message,就将其广播出去。该handler对象收到该消息后,调用相应的handler对象的handleMessage()方法 对其进行处理。

    5、HandlerThread:本质上是线程加消息的实现;

    总结:handler负责发送消息,Looper负责接收handler发送的消息,并直接把消息回传给handler自己,MessageQueue是消息存储的容器。

二、Handler机制:

    1、Handler是什么?

    FAQ:handler是android提供用来更新UI的一套机制,也是一套消息处理的机制,我们可以发送消息,也可以通过它处理消息;

    2、为什么要使用Handler?

    FAQ:android设计的时候就封装了一套消息创建、传递处理的机制,如果不遵循这样的机制就无法更新UI,就会抛出异常。

    3、如何使用Handler?

    FAQ:见Handler常用方法,sendMessage,sendMessageDelayed,post(Runnable),postDelayed(Runnable, long)等。

    4、android设计为什么只能通过Handler机制更新UI呢?

    FAQ:根本目的是解决多线程并发的问题,加锁会导致性能下降;

    5、常见的handler异常分析。

    (1)android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views。

    这个问题主要是在子线程里修改了UI导致的,

(2)Can't create handler inside thread that has not called

    这个问题是在子线程里创建Handler前没有调用Looper.prepare()和looper关联导致的。

    6、如何实现一个与线程相关的Handler?

    FAQ:下面代码实现了在子线程里创建Handler对象。

class MyThread extends Thread {
 public Handler handler;
 @Override
 public void run() {
     Looper.prepare();//没有这段代码会报5中的(2)异常。
     handler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
      System.out.println("currentThread------------->"
       + Thread.currentThread().getId());
  }
     };
     Looper.loop();
 }
    }

    7、如何在主线程给子线程发送消息?

    FAQ:见下面代码,实现了主线程和子线程互发信息。

public class MainActivity extends Activity implements OnClickListener {
    private TextView textView;
    private Button start, stop;
    private Handler thread;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.fragment_main);
 textView = (TextView) findViewById(R.id.textView1);
 start = (Button) findViewById(R.id.Start);
 stop = (Button) findViewById(R.id.Stop);
 start.setOnClickListener(this);
 stop.setOnClickListener(this);
 HandlerThread handlerThread = new HandlerThread("handlerThread");
 handlerThread.start();
 thread = new Handler(handlerThread.getLooper()) {
     @Override
     public void handleMessage(Message msg) {
    Message message = new Message();
  mainHandler.sendMessageDelayed(message, 1000);
  System.out.println("threadHandler---->" + Thread.currentThread().getId());
     }
 };
    }
    // 主线程
    Handler mainHandler = new Handler() {
 public void handleMessage(Message msg) {
     Message message = new Message();
     thread.sendMessageDelayed(message, 1000);
     System.out.println("mainHandler---->" + Thread.currentThread().getId());
 };
    };
    @Override
    public void onClick(View v) {
 if (v == start) {
     mainHandler.sendEmptyMessage(0);
 } else if (v == stop) {
     mainHandler.removeMessages(0);
 }
    }
}

    8、Android中更新UI有几种方式?

    FAQ:常见android中更新UI的方式又以下四种,runOnUIThread ,handler.post ,handler.sendMessage view.post。通过源码去看,实质上都是使用handler机制去处理UI的。

    9、android非UI线程真的不能更新UI吗?

    FAQ:在android非UI现场中真的不能更新UI吗,大家看下下面的代码:

new Thread(){
     public void run() {
  textView.setText("updateview");
     };
 }.start();

运行这段代码,你会神奇地发现更新了UI,再看下面的这段代码:

new Thread(){
     public void run() {
     try{
        Thread.sleep(2000);
      textView.setText("updateview");
     }catch(Exception e){
     }     
         };
 }.start();

    你会神奇地发现报了“5、常见的handler异常分析”中的异常(1),所以不建议在非UI线程中去更新UI。

    10、Handler的Callback用法:

private Handler handler = new Handler(new Callback() {//截获消息
  @Override
  public boolean handleMessage(Message msg) {
   Toast.makeText(getApplicationContext(), "1", 1).show();
   return false;//false会发送两个消息,true,不会处理下面的消息
  }
 }) {
  @Override
  public void handleMessage(Message msg) {
   Toast.makeText(getApplicationContext(), "2", 1).show();
  }
 };
 
handler.sendEmptyMessage(0);

© 著作权归作者所有

二进制的忧伤
粉丝 9
博文 19
码字总数 16902
作品 0
深圳
程序员
私信 提问
Android:关于多线程的总结知识都在这里了!

前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 今天,我将献上一份全面 & 详细的Android多线程学习指南,希望你们喜欢。 目录

Carson_Ho
05/22
0
0
一份关于 Java、Kotlin 与 Android 的学习笔记

JavaKotlinAndroidLearn 这是一份关于 Java 、Kotlin 、Android 的学习笔记,既包含对基础知识点的介绍,也包含对一些重要知识点的源码解析,笔记的大纲如下所示: Java 重拾Java(0)-基础知...

叶应是叶
2018/08/08
0
0
这是一份全面 & 详细的Android多线程知识总结指南

前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 今天,我将献上一份全面 & 详细的Android多线程学习指南,希望你们喜欢。 目录 1. 多线程基础知识 在了解Android多线程实现...

Carson_Ho
06/26
0
0
Android多线程:这是一份全面 & 详细的HandlerThread学习指南

前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 今天,我将献上一份全面 & 详细的机制的学习指南,内容包括:定性认知、定量使用、工作原理 & 源码分析,希望你们会喜欢。...

Carson_Ho
05/16
0
0
C语言自学完备手册(21)——递归

版权声明: https://blog.csdn.net/lfdfhl/article/details/82897146 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–o...

谷哥的小弟
2018/09/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

浅谈Visitor访问者模式

一、前言 什么叫访问,如果大家学过数据结构,对于这点就很清晰了,遍历就是访问的一般形式,单独读取一个元素进行相应的处理也叫作访问,读取到想要查看的内容+对其进行处理就叫作访问,那么...

青衣霓裳
25分钟前
6
0
JS内嵌多个页面,页面之间如何更快捷的查找相关联的页面

假设parent为P页面, P页面有两个子页面,分别为B页面和C页面; B页面和C页面分别内嵌一个iframe,分别为:D页面和E页面 现在通过B页面的内嵌页面D的方法refreshEpage(eUrl)来加载内嵌页面E的内容...

文文1
26分钟前
7
0
Hibernate 5 升级后 getProperties 错误

升级到 Hibernate 5 后,提示有错误: org.hibernate.engine.spi.SessionFactoryImplementor.getProperties()Ljava/util/Map; 完整的错误栈为: java.lang.NoSuchMethodError: org.hibernate......

honeymoose
27分钟前
6
0
mysql-connector-java升级到8.0后保存时间到数据库出现了时差

在一个新项目中用到了新版的mysql jdbc 驱动 <dependency>     <groupId>mysql</groupId>     <artifactId>mysql-connector-java</artifactId>     <version>8.0.18</version> ......

ValSong
30分钟前
6
0
Spring中BeanFactory与FactoryBean的区别

在Spring中有BeanFactory和FactoryBean这2个接口,从名字来看很相似,比较容易搞混。 一、BeanFactory BeanFactory是一个接口,它是Spring中工厂的顶层规范,是SpringIoc容器的核心接口,它定...

大王叫下
33分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部