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

点击打开链接

一、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);


也就是开启循环

Android--Handler使用应运及消息机制处理原理分析_ide


注:


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


 也就是移除相关的消息发送




@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());
}
};


Android--Handler使用应运及消息机制处理原理分析_主线程_02


特别说明:

消息发送说明


在上面的发送消息的时候 ,我们使用的是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
    内部包含一个消息队列,也就是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 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);


然后我们在主线程中执行

可以在控制台上看到

Android--Handler使用应运及消息机制处理原理分析_主线程_03

因为我们在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其实就是一个线程

Android--Handler使用应运及消息机制处理原理分析_Looper_04

然后我们在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--Handler使用应运及消息机制处理原理分析_主线程_05


Android自定义控件ImageViwe(一)——依据控件的大小来设置缩放图片显示

   ​​ 点击查看分析文档​


 Android自定义ImageView(二)——实现双击放大与缩小图片

    ​​ 点击打开链接​


 Android自定义控件ImageViwe(三)——随手指进行图片的缩放

   ​​ 点击打开链接​


 Android自定义控件ImageViwe(四)——多点触控实现图片的自由移动  

    ​​ 点击打开链接​


 Android ListView分组排序显示数据

    ​​ 点击打开链接​


 Android自定义下拉刷新功能的ListView

    ​​ 点击打开链接​


 Android音乐播放器高级开发

    ​​ 点击打开链接​


 Android自定义控件之流式布局

 ​​点击打开链接​


 Android自定义下拉刷新功能的ListView

 ​​点击打开链接​