我们在非UI线程更新UI是会通过以下几种方式来进行的:参考http://vincenttung.blog.51cto.com/6249439/1143761
(1) handler.send(Message msg)或者handler.post(Runnable r)
(2) View.post(runnable r) ,View.PostDelayed(Runnabe,long)
(3) Activity 的runOnUIThread(runnable r)
(4)通过Handlerthread进行更新
(5)在子线程中使用looper.prepare 和 looper.loop()
(6)还有一个很重要的AsyncTask()
1、先来个小插曲:
Android: is View.onClick() method invoked on main UI thread?
Yes it is. And then you launch your crazy networking stuff in a background thread.
也就是说,在onClick 中弹出Toast等是算在main UI thread 里面的。
2、再来一个,android 在非UI thread 中显示toast ,如果不出意外的话,肯定是会弹出
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
提示的,那么要怎么样才能不出错呢?可以这样子!
Looper.prepare();
Toast.makeText(LoginActivity.this,filedId, Toast.LENGTH_LONG).show();
Looper.loop();
为什么能这样子? 请参考:http://blog.csdn.net/xiaanming/article/details/8904645 他会告诉你为什么能这样子,但是
这样子真的好吗?会不会出什么幺蛾子啊?一定要这样子怎么办!?
先上一段代码:
public class TestLooperThread extends Thread {
private String TAG="TestLooperThread";
private Context mContext;
/**
* @param UiMangerHandler
* @param looper
* @param mContext
*/
public TestLooperThread(Handler UiMangerHandler,Looper looper,Context mContext){
this.mContext=mContext;
// start();
}
public void run(){
Log.e(TAG,"TestLooperThread start!");
Looper.prepare();
Toast.makeText(mContext, "Thread is over ? ", Toast.LENGTH_SHORT).show();
Looper.loop();
Log.e(TAG,"TestLooperThread ended! 这个是不会打印出来的...");
}
}
这个线程会在执行完run后结束吗?查看DDMS可以发现,他还是一直活动的!
Log.e(TAG,"TestLooperThread ended! 这个是不会打印出来的..."); 这行代码是不会执行的。查看
Looper.loop();
这行代码干了些什么就知道原因了,下面是loop()的定义
public static void loop() {
Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
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();
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
... ...
... ...
}
}
loop 方法是个死循环啊,他是不会结束的,如果这种线程一直放任下去就会发现一段时间后,总是Crash,tombstones中的堆栈信息成百上千简直不是梦啊!这样子是无法通过压力测试的啊@!
那么要怎样才能结束这个循环呢?
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
如果msg.target== null的话就会结束的啊,Looper class 中有一个quit( )方法
public void quit() {
Message msg = Message.obtain();
// NOTE: By enqueueing directly into the message queue, the
// message is left with a null target. This is how we know it is
// a quit message.
mQueue.enqueueMessage(msg, 0);
}
他就这样让Loop循环结束了!
Tips:Toast 在线程中加loop还会有一个问题,如果没有结束,回调的时候super后面的语句就不会执行了。
因为super 的loop() 方法阻塞了。