最近开通了一个小微博,欢迎大家关注,每天分享一些上班路上看的小知识点

点击打开链接

一、Handler是什么 ?

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

二、Handler的基本使用方法:

使用方法一 (普通更新UI方法)

//在子线程中使用,用来更新UInew Thread(){@Overridepublic void run() {super.run();SystemClock.sleep(3000);mHandler.post(new Runnable() {@Overridepublic void run() {textView.setText("三秒后更新文字");}});}}.start();

这个可以在主线种中直接调用

使用方法二(循环消息更新UI)

private UpdateTextViewRuunable mRuunable = new UpdateTextViewRuunable();private int number = 1;private class UpdateTextViewRuunable implements  Runnable{@Overridepublic void run() {number++;mTextView.setText("一秒更新一次"+number);mHandler.postDelayed(mRuunable,1000);}}

然后再在主线程中进行调用 :

mHandler.postDelayed(mRuunable,1000);

也就是开启循环

注:

我们会发现当我们的应用程序退出的时候,这个线程还是在始终执行着,所以我们要在我们的应用程序退出的时候,停止循环操作
 也就是移除相关的消息发送

 @Overrideprotected void onDestroy() {super.onDestroy();mHandler.removeCallbacks(mRuunable);}

使用方法三(通过Message消息来传递数据)

创建保存数据的信息对象

class Person{public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}

通过handler发送消息并传递相关数据

new Thread(){@Overridepublic void run() {super.run();SystemClock.sleep(3000);mHandler.post(new Runnable() {@Overridepublic void run() {//   textView.setText("三秒后更新文字");Message message = Message.obtain();message.arg1 = 10;message.arg2 = 12;message.obj = new Person("zhaong san",102);mHandler.sendMessage(message);}});}}.start();

在handler中接收发送的消息和相关数据

private Handler mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);final int arg1 = msg.arg1;final int arg2 = msg.arg2;final Person obj = (Person) msg.obj;mTextView.setText("arg1 is "+arg1+"\n+arg2 is"+arg2+"\n person is "+obj.toString());}};

特别说明:

消息发送说明

在上面的发送消息的时候 ,我们使用的是mHandler的sendMessage方法,在这里发送消息,我们也可以使用

message.sendToTarget();

方法进行消息发送,message.sendToTarget方法简析

   /*** Sends this Message to the Handler specified by {@link #getTarget}.* Throws a null pointer exception if this field has not been set.*/public void sendToTarget() {target.sendMessage(this);}

可以看到  message.sendToTarget(); 进行消息发送,实际上是调用了target的sendMessage方法进行消息发送
而这里使用到的target则是我们的一个Handler对象

创建消息对象说明

在这里我们是通过Message.obtain方法来获取一个消息 对象的,这里我们可以简单看一下其源码

 /*** Return a new Message instance from the global pool. Allows us to* avoid allocating new objects in many cases.*/public static Message obtain() {synchronized (sPoolSync) {if (sPool != null) {Message m = sPool;sPool = m.next;m.next = null;m.flags = 0; // clear in-use flagsPoolSize--;return m;}}return new Message();}

Message.obtain()在这里获取到一个Message对象,可以简单看一下其原理,实际上它是取出系统中存在的一个空的message对象,
如果这个对象为空,那么再进行创建

当然我们也可以直接使用new Message来创建一个新的消息对象

三、拦截Handler发送的消息

private  Handler mHandlerTwo = new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {return true;}}){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);}};

在Handler接收发送过来的消息的时候会先回调callback中的handleMessage方法,然后再回调handler的handleMessage方法
当我们在callback的handleMessage方法返回为true时候,就会在callback中进行消息拦截,之后就不会再回调handleMessage方法了

四、Handler原理分析

* Handler主要是分析消息发送,默认情况下就是把消息发送给了自己

*Looper
    内部包含一个消息队列,也就是MessageQueue,所有的Handler发送的消息都走向这个消息队列

Looper.Looper方法,就是一个死循环,不断的从MessageQueue中取消息,如有消息就进行消息处理,没有消息就阻塞

* 总结:
    Handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给Handler自已
    MessageQueue是一个存储消息的容器

* 在默认情况下,我们的应用程序是由ActivityThread来创建的,在ActivityThread中创建我们所有的Activity,并回调我们
Activity的构造方法,ActivytyThread也会默认去创建main线程(也就是主线程),同时也会默认创建一个Looper对象,而在
Looper中也会默认创建一个message对象

*源码分析:

* 我们查看ActivityThread类的main方法,可以看到在这里会首先调用方法  Looper.prepareMainLooper();

* 然后再查看Looper的prepareMainLooper方法

/*** Initialize the current thread as a looper, marking it as an* application's main looper. The main looper for your application* is created by the Android environment, so you should never need* to call this function yourself.  See also: {@link #prepare()}*/public static void prepareMainLooper() {prepare(false);synchronized (Looper.class) {if (sMainLooper != null) {throw new IllegalStateException("The main Looper has already been prepared.");}sMainLooper = myLooper();}}

可以看到 在这里首先调用了prepare方法

/** Initialize the current thread as a looper.* This gives you a chance to create handlers that then reference* this looper, before actually starting the loop. Be sure to call* {@link #loop()} after calling this method, and end it by calling* {@link #quit()}.*/public static void prepare() {prepare(true);}private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));}

* 而在prepare方法中,使用到了sThreadLocal.get()方法
* sThreadLocal主要是用于在我们的线程运行中保存一些变量信息,其主要有set 方法 和get方法 ,set方法就是将我们  创建的变量放到ThreadLocal中
* 而get方法就是将变量拿出来

* 在这里我们默认的UI线程去调用它的get方法,默认情况下是等于null的,所以在这里 set了一个Looper对象

而我们再查看new Loopre的操作

private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mRun = true;mThread = Thread.currentThread();}

可以看到,在我们创建Looper对象的时候,会同时创建一个MessageQueue对象,而在这里的MessageQueue就是我们所有消息的一个消息队列

走到这里,在我们的UI线程中就创建了一个Looper对象和一个MessageQueue对象

然后当我们在应用程序中创建Handler的时候

/*** Default constructor associates this handler with the {@link Looper} for the* current thread.** If this thread does not have a looper, this handler won't be able to receive messages* so an exception is thrown.*/public Handler() {this(null, false);}
 public Handler(Callback callback, boolean async) {...mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}mQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;}

*在这里,无参数的构造会调用有参数的构造方法

*当执行到有两个参数的构造方法中后,首先会Looper.myLooper()方法获取一个Looper对象,

    /*** Return the Looper object associated with the current thread.  Returns* null if the calling thread is not associated with a Looper.*/public static @Nullable Looper myLooper() {return sThreadLocal.get();}

*可以看到这里调用了ThreadLocal.get方法,而上面我们分析到,主线程在进行创建应用程序的过程中会将一个Looper对象存放在ThreadLocal中,
在这里我们通过get方法将其取到,这样,Handler 与Looper 以及 MessageQuquene关联到一起了

*然后呢在我们的Handler的两个参数的构造方法中就可以通过方法  mQueue = mLooper.mQueue; 来拿到这里的MessageQueue消息队列

*当我们调用  mHandler.sendMessage(message);方法进行消息发送的时候

public final boolean sendMessage(Message msg){return sendMessageDelayed(msg, 0);}public final boolean sendMessageDelayed(Message msg, long delayMillis){if (delayMillis < 0) {delayMillis = 0;}return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}public boolean sendMessageAtTime(Message msg, long uptimeMillis) {MessageQueue queue = mQueue;if (queue == null) {RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");Log.w("Looper", e.getMessage(), e);return false;}return enqueueMessage(queue, msg, uptimeMillis);}

我们可以看到最终是调用的sendMessaeAtTime方法;在这里handler会通过当前线程拿到一个MessageQueue消息队列,然后调用下一个方法

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}

在这里我们可以看到 msg.target是一个标识,是指消息要发送给谁,在这里,指向Handler对象本身,然后
调用了queue.euqueueMessage方法将消息放到这个消息队列中去

而在我们的Looper对象中loop方法中

public static void loop() {final Looper me = myLooper();if (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}final MessageQueue queue = me.mQueue;// Make sure the identity of this thread is that of the local process,// and keep track of what that identity token actually is.Binder.clearCallingIdentity();final long ident = Binder.clearCallingIdentity();for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}// This must be in a local variable, in case a UI event sets the loggerPrinter logging = me.mLogging;if (logging != null) {logging.println(">>>>> Dispatching to " + msg.target + " " +msg.callback + ": " + msg.what);}msg.target.dispatchMessage(msg);if (logging != null) {logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);}// Make sure that during the course of dispatching the// identity of the thread wasn't corrupted.final long newIdent = Binder.clearCallingIdentity();if (ident != newIdent) {Log.wtf(TAG, "Thread identity changed from 0x"+ Long.toHexString(ident) + " to 0x"+ Long.toHexString(newIdent) + " while dispatching to "+ msg.target.getClass().getName() + " "+ msg.callback + " what=" + msg.what);}msg.recycleUnchecked();}}

可以看到在这里首先是通过myLooper方法到获取到当前的Looper对象

public static @Nullable Looper myLooper() {return sThreadLocal.get();}

然后再通过Looper对象来拿到我们创建的MessageQueue

然后就是在for循环中不断的取消息,如果取出的消息为null,直接return,如果取出的消息如果不为空,则调用msg.target.dispatchMessage(msg);处理消息

msg.target就是指向消息发送的方向,而在这里默认设置的是Handler本身
而在msg.target.dispatchMessage(msg);方法中

public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}

可以看到在这里首先会去调用callback的handleMessage方法,当这个方法返回true的时候,这里会直接return,也就是说不再会执行本身的handleMessage方法
如果返回 的是false,那么会继续执行本身的handleMessage方法,这就是我们刚刚谈到的拦截handler接收的消息处理过程

Handler主要是封装了消息发送,默认情况下就是把消息发送给了自己

Looper
    内部包含一个消息队列,也就是MessageQueue,所有的Handler发送的消息都走向这个消息队列

Looper.Looper方法,就是一个死循环,不断的从MessageQueue中取消息,如有消息就进行消息处理,没有消息就阻塞

总结:

Handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给Handler自已
    MessageQueue是一个存储消息的容器

在默认情况下,我们的应用程序是由ActivityThread来创建的,在ActivityThread中创建我们所有的Activity,并回调我们
    Activity的构造方法,ActivytyThread也会默认去创建main线程(也就是主线程),同时也会默认创建一个Looper对象,而在
    Looper中也会默认创建一个message对象

创建一个与子线程绑定的Handler

class  CustomThread extends  Thread{//定义一个Handlerpublic Handler mHandler;@Overridepublic void run() {super.run();Looper.prepare();mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);}};Looper.loop();}
}

在使用的时候可直接创建CustomThread对象,然后通过对象来调用我们的线程Handler

创建一个子线程,并指定其中的一个Looper对象

class  CustomThread extends  Thread{//定义一个Handlerpublic Handler mHandler;private Looper mLooper;@Overridepublic void run() {super.run();Looper.prepare();mLooper = Looper.myLooper();mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);}};Looper.loop();}
}

在主线程中进行调用

 final CustomThread customThread = new CustomThread();customThread.start();customThread.mHandler.sendEmptyMessage(0);final Handler handler = new Handler(customThread.mLooper){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);}};handler.sendEmptyMessage(0);

这样直接调用的时候,程序会抛出空指针异常,也就 是说当我们在主线程中调用 子线程(CustomThread)的Looper的时候,当我们的Looper对象还没有被创建出来的时候,然后我们主线程中的另一个Handler就使用到了,所以..

为了解决这样的问题,我们可以使用

private HandlerThread mHandlerThread;
private Handler mHandler;mHandlerThread = new HandlerThread("custumThread");mHandlerThread.start();mHandler = new Handler(mHandlerThread.getLooper()){@Overridepublic void handleMessage(Message msg) {System.out.println("Thread.currentThread name is "+Thread.currentThread());}};mHandler.sendEmptyMessage(1);

然后我们在主线程中执行

可以在控制台上看到

因为我们在new HandlerThread的时候就 定义了我们线程的名字

我们可以看一下在这里使用到的mHandlerThread.gtLooper方法

public Looper getLooper() {if (!isAlive()) {return null;}// If the thread has been started, wait until the looper has been created.synchronized (this) {while (isAlive() && mLooper == null) {try {wait();} catch (InterruptedException e) {}}}return mLooper;}

调用这个方法的时候,首先会去判断下当前线程是否为空

因为我们当前的HandlerThread其实就是一个线程

然后我们在getLooper方法中可以看到接下来就是判断当Looper对象为空的时候,使当前线程处于等待状态

在HandlerThread的run方法中

public void run() {mTid = Process.myTid();Looper.prepare();synchronized (this) {mLooper = Looper.myLooper();notifyAll();}Process.setThreadPriority(mPriority);onLooperPrepared();Looper.loop();mTid = -1;}

可以看到这里创建了一个Looper对象,并且唤醒了我们的线程

主线程与子线程进行通信

public class ThreadMainToChildActivity extends Activity  {//创建主线程的Handlerprivate Handler mMainHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);System.out.println("主线程中Handler执行的方法");final Message message = Message.obtain();//向子线程中发送消息mChildHandler.sendMessageDelayed(message, 1000);}};private HandlerThread mChildThread;private Handler mChildHandler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main_thread_to_child);mChildThread = new HandlerThread("childThread");mChildThread.start();//创建子线程的HandlermChildHandler = new Handler(mChildThread.getLooper()){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);System.out.println("子线程中执行的方法");final Message message = Message.obtain();//主线程Handler发送消息mMainHandler.sendMessageDelayed(message,1000);}};mMainHandler.sendEmptyMessage(1);}
}

运行

Android自定义控件ImageViwe(一)——依据控件的大小来设置缩放图片显示
   点击查看分析文档
    
 Android自定义ImageView(二)——实现双击放大与缩小图片
    点击打开链接
    
 Android自定义控件ImageViwe(三)——随手指进行图片的缩放
   点击打开链接
    
 Android自定义控件ImageViwe(四)——多点触控实现图片的自由移动  
    点击打开链接
    
 Android ListView分组排序显示数据
    点击打开链接
    
 Android自定义下拉刷新功能的ListView
    点击打开链接
    
 Android音乐播放器高级开发
    点击打开链接
    
 Android自定义控件之流式布局
 点击打开链接

Android自定义下拉刷新功能的ListView
 点击打开链接

Android--Handler使用应运及消息机制处理原理分析相关推荐

  1. android handler的机制和原理_一文搞懂handler:彻底明白Android消息机制的原理及源码

    提起Android消息机制,想必都不陌生.其中包含三个部分:Handler,MessageQueue以及Looper,三者共同协作,完成消息机制的运行.本篇文章将由浅入深解析Android消息机制的运 ...

  2. android qq功能实现原理,Android QQ、微信聊天消息界面设计原理与实现

     Android QQ.微信聊天消息界面设计原理与实现 原理:Android平台上,典型的以腾讯的QQ.微信这些聊天消息界面通常可以采用ListView设计与实现,需要使用ListView 适配器 ...

  3. 事件争夺战 Android事件处理机制与原理分析

    事件争夺战 Android事件处理机制与原理分析 文章目录 事件争夺战 Android事件处理机制与原理分析 View的继承关系 View的事件处理源码 总结: ViewGroup的事件分发源码 总结 ...

  4. Redis数据持久化机制AOF原理分析一---转

    http://blog.csdn.net/acceptedxukai/article/details/18136903 http://blog.csdn.net/acceptedxukai/artic ...

  5. Redis数据持久化机制AOF原理分析二

    本文所引用的源码全部来自Redis2.8.2版本. Redis AOF数据持久化机制的实现相关代码是redis.c, redis.h, aof.c, bio.c, rio.c, config.c 在阅 ...

  6. 分布式消息通信ActiveMQ原理 分析一

    本章知识点: 1. 持久化消息和非持久化消息的发送策略2. 消息的持久化方案及实践3. 消费端消费消息的原理 持久化消息与非持久化消息的发送策略 消息同步发送和异步发送 同步发送过程中,发送者发送一条 ...

  7. 消息队列NetMQ 原理分析2-IO线程和完成端口

    目录 前言 介绍 目的 IO线程 初始化IO线程 Proactor 启动Procator线程轮询 处理socket IOObject 总结 前言 介绍 [NetMQ](https://github.c ...

  8. Java 数据交换格式反射机制SpringIOC原理分析

    数据交换格式&反射机制&SpringIOC原理分析 什么是数据交换格式? 数据交换格式使用场景 JSON简单使用 什么是JSON? JSON格式的分类 常用JSON解析框架 使用fas ...

  9. android 结束if循环_Android 消息机制(Handler + MessageQueue + Looper)

    Author:CrazyWah Date:2018.03.26 CopyRight:http://crazywah.com 禁止搬运!!!禁止搬运!!!禁止搬运!!! Android的消息机制主要由H ...

最新文章

  1. python中类的约束和限制对象添加属性
  2. mysql 新建数据库
  3. 郑州升达经贸管理学院计算机专业学费,郑州升达经贸管理学院学费
  4. 小程序【笔记002】逻辑层简介
  5. 递归函数合式分解python_python(22)- 递归和函数式编程
  6. PHP获取input中的值相同报错,laravel单元测试之phpUnit中old()函数报错解决_php实例...
  7. devops 三十六计_DevOps从业人员应遵循的16个博客和新闻通讯
  8. 跑代码时出错:tensorflow.python.framework.errors_impl.UnknownError: 2 root error(s) found. (0) Unknown……
  9. C# 中将所有引用的DLL 和exe文件打成一个exe文件(转)
  10. 房间WIFI信号不好怎么办?——无线路由桥接(WDS)
  11. 新浪微博指数查询API接口文档
  12. Pr 视频效果:过时
  13. 影片剪辑实例名的几点注意
  14. mysql sql 语法错误_执行SQL查询时出现MySQL语法错误
  15. uni-app uView UI框架 下载安装教程
  16. 【学习日志】2023.04.24 C++ 调整黑点、白点和中值以增加、平衡或降低对比度
  17. 瑞星卡卡升级出现错误:kmon.dll.zip,错误代码:0x0/0x0(chech)
  18. 我女儿说要看雪,于是我默默的拿起了键盘,下雪咯,程序员就是可以为所欲为!
  19. 征服上司站稳脚13招
  20. Java 数据转换/进制转换 工具类

热门文章

  1. 【提醒】刷脸取件被小学生“破解”!丰巢紧急下线
  2. 获取mysql所有用户权限_查看MYSQL数据库中所有用户及拥有权限
  3. 【python项目实战入门】Python绘制爱心
  4. java 父类this_java父类方法中使用this,可以把this强转为子类对象,然后调用子类的实例方法,怎么解释?...
  5. 最佳论文!牛津大学揭示梯度下降复杂度理论
  6. 清华 | 量化卷积神经网络加速芯片
  7. 笔记 | 《机器学习》中计算学习理论(上)
  8. EfficientNet 解析:卷积神经网络模型尺度变换的反思
  9. Github | 人脸识别手册 (分类论文集)
  10. 北大师兄告诉你,怎样顺利完成自己的博士生涯