我们在非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、先来个小插曲:
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() 方法阻塞了。