Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one,
call prepare()
in the thread that is to run the loop, and then loop()
to have it process messages until the loop is stopped.
1 class LooperThread extends Thread { 2 public Handler mHandler; 4 public void run() { 5 Looper.prepare(); 7 mHandler = new Handler() { 8 public void handleMessage(Message msg) { 9 // process incoming messages here 10 } 11 }; 13 Looper.loop(); 14 } 15 }
(1)提出问题:正如上面所说, 一个线程默认是没有Looper用来处理message队列的。但为什么我们在主线程时又没有自己创建Looper呢?
1 public class Looper { 2 private static final String TAG = "Looper"; 3 4 // sThreadLocal.get() will return null unless you've called prepare(). 5 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); //(1)又见到了眼熟的ThreadLocal,里面存放的是每个线程的Looper 6 private static Looper sMainLooper; // guarded by Looper.class 7 8 final MessageQueue mQueue; 9 final Thread mThread; 10 volatile boolean mRun; 11 12 private Printer mLogging; 13 14 /** Initialize the current thread as a looper. 15 * This gives you a chance to create handlers that then reference 16 * this looper, before actually starting the loop. Be sure to call 17 * {@link #loop()} after calling this method, and end it by calling 18 * {@link #quit()}. 19 */ 20 public static void prepare() { 21 prepare(true); 22 } 23 24 private static void prepare(boolean quitAllowed) { 25 if (sThreadLocal.get() != null) { 26 throw new RuntimeException("Only one Looper may be created per thread"); 27 } 28 sThreadLocal.set(new Looper(quitAllowed)); 29 } 30 31 /** 32 * Initialize the current thread as a looper, marking it as an 33 * application's main looper. The main looper for your application 34 * is created by the Android environment, so you should never need 35 * to call this function yourself. See also: {@link #prepare()} 36 */ 37 public static void prepareMainLooper() { 38 prepare(false); 39 synchronized (Looper.class) { 40 if (sMainLooper != null) { 41 throw new IllegalStateException("The main Looper has already been prepared."); 42 } 43 sMainLooper = myLooper(); //(2)为主线程的Looper赋值 44 } 45 } 46 47 /** Returns the application's main looper, which lives in the main thread of the application. 48 */ 49 public static Looper getMainLooper() { 50 synchronized (Looper.class) { 51 return sMainLooper; 52 } 53 } 54 55 56 /** 57 * Return the Looper object associated with the current thread. Returns 58 * null if the calling thread is not associated with a Looper. 59 */ 60 public static Looper myLooper() { //(3)为主线程Looper赋值的其实就是调用ThreadLocal的get() 61 return sThreadLocal.get(); 62 } 63 64 65 }
2.如果不知道ThreadLocal是什么意思,自己去查API,我没这么大气和你讲。
3.所以我们可以这样用:
1 public class MainActivity extends Activity { 2 3 4 private ProgressDialog mpDialog; 5 private int mCount = 0; 6 7 private Handler handler = new Handler(){ 8 9 @Override 10 public void handleMessage(Message msg) { 11 //update UI 12 System.out.println("----------update ui ok--------------"+Thread.currentThread().getId()); // Thread id 为1 说明在主线程中执行。 13 System.out.println("message arg1 : "+ msg.arg1); //因为这是主线程,所以可以在这时更新UI 14 super.handleMessage(msg); 15 } 16 }; 17 18 private Thread downThread = new Thread(){ 19 20 @Override 21 public void run() { 22 23 try{ 24 while(mCount<=100){ 25 mpDialog.setProgress(mCount++); 26 Thread.sleep(100); //模拟下载过程 27 } 28 // This is essentially the same as calling dismiss(), 29 //but it will also call your DialogInterface.OnCancelListener (if registered). 30 mpDialog.cancel(); 31 System.out.println("------------download ok----------"); 32 Message message = handler.obtainMessage(); 33 message.arg1 = 10; 34 handler.sendMessage(message); 35 }catch(Exception ex){ 36 mpDialog.cancel(); 37 } 38 } 39 40 }; 41 42 @Override 43 protected void onCreate(Bundle savedInstanceState) { 44 super.onCreate(savedInstanceState); 45 setContentView(R.layout.activity_main); 46 Button button= (Button) this.findViewById(R.id.button); 47 imageView = (ImageView) this.findViewById(R.id.imageView01); 48 button.setOnClickListener(new OnClickListener(){ 49 50 @Override 51 public void onClick(View view) { 52 System.out.println("--------------download start----------------"+Thread.currentThread().getId()); //主线程的id为1 53 mCount = 0; 54 mpDialog = new ProgressDialog(MainActivity.this); 55 mpDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 56 mpDialog.setTitle("dialogʾ"); 57 mpDialog.setIcon(R.drawable.ic_launcher); 58 mpDialog.setMessage("好消息"); 59 mpDialog.setMax(100); 60 mpDialog.setProgress(0); 61 mpDialog.setSecondaryProgress(50); 62 mpDialog.setIndeterminate(false); 63 mpDialog.setCancelable(true); 64 mpDialog.setButton("取消", new DialogInterface.OnClickListener(){ 65 66 @Override 67 public void onClick(DialogInterface dialog, int which) { 68 dialog.cancel(); 69 70 } 71 72 }); 73 downThread.start(); 74 mpDialog.show(); 75 } 76 77 }); 78 } 79 80 }
4.正如上面所说,一个新线程在默认情况下是没有Looper相关联的。所以需要自己创建。但android提供了一个HandlerThread,方便我们使用Looper。
1 public class HandlerThread extends Thread { 2 3 Looper mLooper; 4 5 6 /** 7 * Call back method that can be explicitly overridden if needed to execute some 8 * setup before Looper loops. 9 */ 10 protected void onLooperPrepared() { 11 } 12 13 public void run() { 14 mTid = Process.myTid(); 15 Looper.prepare(); 16 synchronized (this) { 17 mLooper = Looper.myLooper(); 18 notifyAll(); 19 } 20 Process.setThreadPriority(mPriority); 21 onLooperPrepared(); 22 Looper.loop(); 23 mTid = -1; 24 } 25 26 /** 27 * This method returns the Looper associated with this thread. If this thread not been started 28 * or for any reason is isAlive() returns false, this method will return null. If this thread 29 * has been started, this method will block until the looper has been initialized. 30 * @return The looper. 31 */ 32 public Looper getLooper() { 33 if (!isAlive()) { 34 return null; 35 } 36 37 // If the thread has been started, wait until the looper has been created. 38 synchronized (this) { 39 while (isAlive() && mLooper == null) { 40 try { 41 wait(); 42 } catch (InterruptedException e) { 43 } 44 } 45 } 46 return mLooper; 47 } 48 49 50 }