您的位置:首页 > 移动开发 > Android开发

android 之 Handler 详解----(一)实现的消息传递基本原理(流程分析)

2015-04-25 23:50 549 查看
Handler可以说是android 中必需掌握的一个点,是android 提供的一套完整的消息传递的机制。我们常见的有用于 UI 的更新。

近来对相关的源代码以及使用进行了了解,记录以下几点:

(一)实现的基本原理

(二)常见的使用的基本方式

(三)更新UI的方法

(一)实现的消息传递基本原理(流程分析)

Handler 实现的离不开Looper 以及 MessageQueue,总结来说是:

1.Handler负责消息的发送,Looper负责接收Handler发送的消息,并且直接回传给Handler自己来处理消息。

2.Looper创建的时候会关联一个MessageQueue 的一个存储消息的容器,负责消息的存储。

以下是以main 线程(UI线程)的handler 以及 Looper为例,讲解一下handler消息是如何传递的。

主要的流程如下:

线程创建-----> Looper的创建 ----> handler 与 Looper的关联----->handler 发送消息----->通过Looper以及messageQueue----->回传给自己handler自己处理消息。

下面是详细的流程讲解:

(首先看看以下简单的handler的使用代码)

<例子>

public class MainActivity extends Activity {

//UI线程中的handler处理
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
if (msg.what == 1) {
System.out.println("main thread-----UI thread");
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//子线程
new Thread(){
@Override
public void run() {
Message msg = new Message();
msg.what = 1 ;
//通过主线程的handler对象,发消息回自己处理
handler.sendMessage(msg);
}
}.start();
}
}


在一个线程中,使用handler 必须要创建相关联的 Looper 来一起使用,不然系统会抛出异常。那为什么在main线程(UI线程)中没有Looper的相关操作呢?其实在main线程(UI线程)在其创建的时候,就已经对looper进行的操作,我们在源代码中查看一下:

<A> . ActivityThread.java中的main函数如下:

Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}

ActivityThread thread = new ActivityThread();
thread.attach(false);

if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}

Looper.loop();


主线程在在创建的时候,其中的main方法调用的时候,已经对Looper进行了关联,下面我们跟踪进

入Looper.prepareMainLooper,进入到prepareMainLooper,里面,发现里面有个prepare 方法,以下是prepare()方法的具体代码:

< B > Looper.java

public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper();
}
public static void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
myLooper().mQueue.mQuitAllowed = false;
}
private synchronized static void setMainLooper(Looper looper) {
mMainLooper = looper;
}
在进入looper之中,prepare方法新建了一个 Looper ,然后后面给了mMainLooper,这个时候main线程中的Looper已经准备好了,准备好了,后面就可以使用了。

而在 new Looper()中,还创建了一个MessageQueue:

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


到此为止,UI线程中已经建立了Looper 以及messageQueue了。

在我们的事例代码中,有中new Handler的操作,深入源代码中,查找,里面会发现,里面就是和相应的Looper进行了关联,也关联相关的MessageQueue,Handler中的构造函数:

< C > Handler.java

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 = null;


<例子>中UI线程新建一个handler 的操作,实际也和Looper而进行了关联,然后在oncreate中新建一个线程,通过handler中的sendMessage()方法进行消息的发送操作,下面就开始看看,消息是如何发送回来 handler自身的。

< D >... Handler.java MessageQueue.java

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)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}


消息已经保存到了MessageQueue中去了,然后Looper的作用就开始了,Looper就是要把MessageQueue中的消息轮询的方式发送出去,
往回看一下 <A> 中的代码,最后的时候,调用了 Looper.loop(),这个作用到底是什么呢?没错,这个就是Looper要传消息了,我们深入看看其中的代码:

<E> Looper.java

public static void loop(){
Looper me = myLooper();
...
MessageQueue queue = me.mQueue;

...

while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
...

msg.target.dispatchMessage(msg);

...

msg.recycle();
}
}
}


上面的代码重点在 轮询 messageQueue里面的message ,然后就是调用msg.target.dispatchMessage(msg), 这个就会发现这个消息回传到了UI线程中的handler了


<F> Handler.java

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


这个时候,消息就重新发回到handler自身的handleMessage 方法中了,消息大功告成的传了回来。

上面是叙述了UI线程中的handler消息的回传的流程,一样的如果我们需要在一个新建的线程中,创建一个handler 来接收其他线程或者UI线程传过来的消息,必须对 Looper进行操作,Looper.prepare()以及Looper.loop()的操作,不然与这个线程不能关联到。UI线程中,只是预先帮我们做了。 当然其实还有另外的方法不用我们自己手动进行,而且可以更加的安全,那个就是HandlerThread,这个后续我关于Handler的使用的帖子,对此进行记录,我的学习状态。

原创,如需转载请标明出处,谢谢~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: