Android--Handler使用应运及消息机制处理原理分析
来源:互联网 发布:ibarn网盘系统源码 编辑:程序博客网 时间:2024/04/28 15:49
最近开通了一个小微博,欢迎大家关注,每天分享一些上班路上看的小知识点
点击打开链接
一、Handler是什么 ?
handler是android给我们提供的一套用来更新UI的一套机制,也是一套消息处理机制,我们可以发送消息,也可以通过它处理消息
二、Handler的基本使用方法:
使用方法一 (普通更新UI方法)
//在子线程中使用,用来更新UI new Thread(){ @Override public void run() { super.run(); SystemClock.sleep(3000); mHandler.post(new Runnable() { @Override public void run() { textView.setText("三秒后更新文字"); } }); } }.start();这个可以在主线种中直接调用
使用方法二(循环消息更新UI)
private UpdateTextViewRuunable mRuunable = new UpdateTextViewRuunable(); private int number = 1; private class UpdateTextViewRuunable implements Runnable{ @Override public void run() { number++; mTextView.setText("一秒更新一次"+number); mHandler.postDelayed(mRuunable,1000); } }
然后再在主线程中进行调用 :
mHandler.postDelayed(mRuunable,1000);
也就是开启循环
注:
我们会发现当我们的应用程序退出的时候,这个线程还是在始终执行着,所以我们要在我们的应用程序退出的时候,停止循环操作也就是移除相关的消息发送
@Override protected 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; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }}
通过handler发送消息并传递相关数据
new Thread(){ @Override public void run() { super.run(); SystemClock.sleep(3000); mHandler.post(new Runnable() { @Override public 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(){ @Override public 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 flag sPoolSize--; return m; } } return new Message(); }
Message.obtain()在这里获取到一个Message对象,可以简单看一下其原理,实际上它是取出系统中存在的一个空的message对象,
如果这个对象为空,那么再进行创建当然我们也可以直接使用new Message来创建一个新的消息对象
三、拦截Handler发送的消息
private Handler mHandlerTwo = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { return true; } }){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } };
在Handler接收发送过来的消息的时候会先回调callback中的handleMessage方法,然后再回调handler的handleMessage方法
当我们在callback的handleMessage方法返回为true时候,就会在callback中进行消息拦截,之后就不会再回调handleMessage方法了
四、Handler原理分析
* Handler主要是分析消息发送,默认情况下就是把消息发送给了自己
Looper.Looper方法,就是一个死循环,不断的从MessageQueue中取消息,如有消息就进行消息处理,没有消息就阻塞
*Looper
内部包含一个消息队列,也就是MessageQueue,所有的Handler发送的消息都走向这个消息队列
* 总结:
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 block if (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 logger Printer 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{ //定义一个Handler public Handler mHandler; @Override public void run() { super.run(); Looper.prepare(); mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; Looper.loop(); }}
在使用的时候可直接创建CustomThread对象,然后通过对象来调用我们的线程Handler
创建一个子线程,并指定其中的一个Looper对象
class CustomThread extends Thread{ //定义一个Handler public Handler mHandler; private Looper mLooper; @Override public void run() { super.run(); Looper.prepare(); mLooper = Looper.myLooper(); mHandler = new Handler(){ @Override public 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){ @Override public 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()){ @Override public 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 { //创建主线程的Handler private Handler mMainHandler = new Handler(){ @Override public 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; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_thread_to_child); mChildThread = new HandlerThread("childThread"); mChildThread.start(); //创建子线程的Handler mChildHandler = new Handler(mChildThread.getLooper()){ @Override public 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使用应运及消息机制处理原理分析
- Handler消息处理机制--原理分析
- Android异步消息处理机制详解及源码分析 Handler
- android中的消息机制--浅谈Handler的原理及使用
- Android中Handler消息处理机制原理
- android 消息机制 Handler Looper 原理分析
- Android Handler消息机制原理及总结
- Android应用程序消息处理机制Handler分析
- Handler消息处理机制原理
- handler消息处理机制原理
- Android 消息机制--Handler机制(二)四大原理分析
- Android开发知识(五)消息处理机制Handler+Looper+MessageQueue的原理分析(上)
- Android开发知识(六)消息处理机制Handler+Looper+MessageQueue的原理分析(下)
- Android消息机制(Handler原理)
- 异步消息处理机制-Android中Handler原理(续)
- Android之handler异步消息处理机制原理
- Android Handler消息处理机制
- Android---Handler消息处理机制
- HDU 5323 Solve this interesting problem(DFS)
- <算法> 第一章 基础
- 笔记本电脑因安装软件重启导致黑屏?
- SPOJ QTREE(树链剖分)
- jsoncpp的输出顺序
- Android--Handler使用应运及消息机制处理原理分析
- UVa1388 - Graveyard
- 多态的弊端
- hdoj 1040 As Easy As A+B 【归并排序】
- eclipse 修改控制台 编码
- HYSBZ 1036(树链剖分)
- DayDayUP_Linux运维学习_ftp安装使用
- Android 学习之四大组件(二)——service
- [POJ 1164] The Castle 位运算加搜索