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

android异步消息处理机制

2014-09-11 23:23 351 查看
如果尝试在程序里创建两个Handler对象,一个在主线程中创建,一个在子线程创建.

public class MainActivity extends ActionBarActivity {

private Handler mh1;
private Handler mh2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mh1=new Handler();
new Thread(new Runnable() {
@Override
public void run() {
mh2=new Handler();
}
}).start();
}
} 运行程序会发现,在子线程中创建的Handler的对象会导致程序崩溃,报错如下:

说的是不能再没有Looper.prepare()的线程中创建Handler对象.
如果在子线程中调用了Looper.prepare().

public class MainActivity extends ActionBarActivity {

private Handler mh1;
private Handler mh2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mh1=new Handler();
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
mh2=new Handler();
}
}).start();
}
再运行.就不会出现这个问题了.看看Handler的无参构造函数.

public Handler() { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } 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; } 可以看到 ,mLooper是Looper的对象,如果mLooper为空,就会抛出一个运行异常.提示的错误正是刚才运行的错误.再看一下,什么时候Looper对象才为空public static final Looper myLooper() { return (Looper)sThreadLocal.get(); } 方法很简单,就是从sThreadLocal取出Looper,如果sThreadLocal存在Looper则返回looper对象,否则返回空.结合上面运行,第一遍因为没有Looper.prepare()方法而报Looper对象为空, 第二遍因为有了Looper.prepare()而不会出现这种情况.所以sThreadLocal里面的Looper对象肯定是Looper.prepare()方法传进去的.Looper.prepare()方法源码:public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); } 在这里,可以看到sThreadLocal首先判断是否有Looper对象,如果已经有了,则抛出异常,否则创建一个Looper对象set进去.看出,每个线程中最多只能有一个Looper对象.
看看刚才的代码,发现只有子线程中调用了Looper.prepare()方法,主线程并没有调用.这是因为在程序启动时,系统已经自动调用了Looper.prepare()方法.查看ActivityThread中的main()方法
public static void main(String[] args) { SamplingProfilerIntegration.start(); CloseGuard.setEnabled(false); Environment.initForCurrentUser(); EventLogger.setReporter(new EventLoggingReporter()); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } AsyncTask.init(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } 可以看到这里有一个Looper.prepareMainLooper()方法.再看到这个方法内部
public static final void prepareMainLooper() { prepare(); setMainLooper(myLooper()); if (Process.supportsProcesses()) { myLooper().mQueue.mQuitAllowed = false; } } 到这里,已经明白:主线程中始终会存在一个Looper对象,而在子线程中需要调用Looper.prepare()去创建.

再看Handler是如何发送消息

public class MainActivity extends ActionBarActivity {

private Handler mh1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mh1=new Handler();
new Thread(new Runnable() {
@Override
public void run() {
Message meg=Message.obtain();
meg.obj="data";
mh1.sendMessage(meg);
}
}).start();
}
} 在线程中,用Handler对象发送一个Message.可是,Handler到底是把Message发送到哪里?为什么又会在Handler的handleMessage()方法中可以获取这条Message.其实Handler提供了多个发送消息的方法,除了sendMessageAtFrontOfQueue()外,所有方法都到经过sendMessageAtTime()方法.sendMessageAtTime()源码如下: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; } 方法接受两个参数,第一个就是Message对象,第二个则是需要延迟发送的毫秒数.如果不是调用的sendMessageDelayed(),延迟数都为0.MessageQueue,是一个消息队列.提供了出队与入队的方法.而这里面的enqueueMessage就是入队方法.
final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException(msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.target == null) { mQuiting = true; } msg.when = when; Message p = mMessages; if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; this.notify(); } else { Message prev = null; while (p != null && p.when <= when) { prev = p; p = p.next; } msg.next = prev.next; prev.next = msg; this.notify(); } } return true; }
MessageQueue并没有使用一个集合将所有的消息保存起来,它只使用了mMessages对象表示未处理的消息.其实入队的方法就是将所有的消息按uptimeMillis时间排序,具体操作方法根据时间顺序调用msg.next.而从每一个消息指定它的下一个消息是什么.而出队的方法,就在Looper.loop()方法.
public static final void loop() { Looper me = myLooper(); MessageQueue queue = me.mQueue; while (true) { Message msg = queue.next(); // might block if (msg != null) { if (msg.target == null) { return; } if (me.mLogging!= null) me.mLogging.println( ">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what ); msg.target.dispatchMessage(msg); if (me.mLogging!= null) me.mLogging.println( "<<<<< Finished to " + msg.target + " " + msg.callback); msg.recycle(); } } } 从代码的 while(true) 开始就是一个死循环,然后不停的调用MessageQueue的next方法,next()就是消息队列出队的方法.它的简单逻辑就是如果当前MessageQueue中存在mMessages(待处理消息) ,就将这个消息出队,然后让下一个消息成为mMessages,否则就形成一个堵塞状态,一直等到有新消息入队.
每当一个消息出队,就将它传递到msg.target的dispatchMessage()方法中.而msg.target就是Handler对象.
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }如果mCallback不为空,则调用mCallBack的handleMessage()方法,否则调用Handler的handleMessage()方法.

除了发送消息,还有几种方法可以在子线程中更新UI1.Handler的post()方法
2.View的post()方法
3.Activity的runOnUiThread()方法.

来自为知笔记(Wiz)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐