一个Handler能够发送、处理和线程的消息队列关联的Message和Runnable对象。每个Handler实例与一个线程以及这个线程的消息队列相关。当建立一个新的Handler对象,它就会绑定到建立它的线程/消息队列。它能够分发Message对象和Runnable对象到主线程中。
java
Handler包含了两个队列,一个是线程队列,一个是消息队列。使用post方法会将线程对象放到该handler的线程队列中,使用sendMessage(Message message)将消息放到消息队列中。handler.post(r)并无单独开启一个新的线程,而是仍然在当前Activity线程中执行,handler只是调用了Runnable对象的run方法。android
它有两个做用:canvas
安排Message对象和Runnable对象在线程的指定位置执行安全
使一个action在其余线程中执行并发
当应用程序启动时,Android首先会开启一个主线程(UI线程),主线程管理界面中的UI控件。如界面上有一个Button, 点击button时,android会分发事件来响应操做,这个过程都是在主线程中进行。这时若是须要一个耗时的操做,那么界面会出现假死现象,若是5s没完成,android系统会给一个错误提示"强制关闭"。因此应该把这些耗时的操做放在一个子线程中,由于子线程的操做涉及到UI更新,而主线程是线程不安全的,能够用Handler解决。由于Handler运行在主线程中,它和子线程能够经过Message对象来传递数据。Handler负责接收子线程传过来的Message对象(子线程中经过sendMessage()传递),而后把消息放入主线程队列中,配合主线程更新UI.ide
例一:oop
public class ProgressBarActivity extends Activity { ProgressBar pb; Button begin; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.progressbar); pb = (ProgressBar) findViewById(R.id.pb); pb.setMax(100); begin = (Button)findViewById(R.id.begin); begin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { pb.setVisibility(View.VISIBLE); //⑴点击begin按钮,将要执行的线程对象myThread放到线程队列中 handler.post(myThread); } }); } Handler handler = new Handler(){ //⑷执行handleMessage public void handleMessage(Message msg) { pb.setProgress(msg.arg1); //当进度条已满,将线程对象从队列中移除 if(msg.arg1==pb.getMax()){ handler.removeCallbacks(myThread); }else{ handler.post(myThread); } } }; //⑵线程开始执行 Runnable myThread = new Runnable() { int i = 0; public void run() { System.out.println("begin thread"); i+=10; Message msg = handler.obtainMessage(); msg.arg1 = i; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //⑶将Message对象加入到消息队列中,handler接收消息一定要执行handleMessage(Message msg) handler.sendMessage(msg); if(i==100){ //当i==100,将线程对象从队列中移除,因为handler接收消息会执行handleMessage,因此此处的代码无心义 handler.removeCallbacks(myThread); } } }; }
若是上面的代码中,handleMessage(Message msg)修改成:post
public void handleMessage(Message msg) { pb.setProgress(msg.arg1); handler.post(myThread); }
那么在i=100时,虽然线程中执行了handler.removeCallbacks(myThread),当时仍然会继续run方法,继续打印begin thread。由于在线程的run方法执行后在handleMessage里,handler.post(myThread)又把线程加入线程队列,因此仍然会继续执行线程。this
以上代码的执行过程:点击begin按钮后,将myThread线程对象加入到线程队列中,线程执行,并发出Handler消息通知UI更新,Handler接收消息执行handleMessage,更新UI。spa
注意:若是handler要接收消息,那么就得执行handleMessage方法。
例二:
public class AHandler extends Activity { Handler handler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); handler.post(r); Log.d("M====>", "main"); setContentView(R.layout.main); } Runnable r = new Runnable() { @Override public void run() { Log.d("T====>","tread"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }; } 执行结果: M====> main T====> tread Handler在主线程,因此不管在onCreate()方法里handler.post(r)不管出于那个位置,在执行时,是在主线程中添加r消息队列,而不是另外开启一条新线程,主线程代码执行完毕,就执行线程r。 因此先打印M====> main,而后再打印线程r里的T====> tread
例三:忽略BoundView class( onDraw(Canvas canvas) )
public class BounceActivity extends Activity { protected static final int GUIUPDATEIDENTIFIER = 0x101; BounceView bounceView = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.bounceView = new BounceView(this); this.setContentView(this.bounceView); new Thread(new MyThread()).start(); } Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case BounceActivity.GUIUPDATEIDENTIFIER: bounceView.invalidate(); break; } super.handleMessage(msg); } }; class MyThread implements Runnable{ @Override public void run() { while(!Thread.currentThread().isInterrupted()){ Message msg = new Message(); msg.what = BounceActivity.GUIUPDATEIDENTIFIER; BounceActivity.this.handler.sendMessage(msg); try { Thread.sleep(3000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } } } 运行正常. 在主线程中new Thread(new MyThread()).start()开启了一条新的线程。 虽然在run()方法中循环执行handler.sendMessage(),由于这个操做处于子线程中,因此主线程的handler的Looper监听到有消息,就会执行handleMessage()
例四: 将例三的代码作了修改。
onCreate()方法里将new Thread(new MyThread()).start()修改成handler.post(r).
public class BounceActivity extends Activity { protected static final int GUIUPDATEIDENTIFIER = 0x101; BounceView bounceView = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.bounceView = new BounceView(this); this.setContentView(this.bounceView); handler.post(r); } Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case BounceActivity.GUIUPDATEIDENTIFIER: bounceView.invalidate(); break; } super.handleMessage(msg); } }; Runnable r = new Runnable() { @Override public void run() { while(!Thread.currentThread().isInterrupted()){ Message msg = handler.obtainMessage(); msg.what = BounceActivity.GUIUPDATEIDENTIFIER; handler.sendMessage(msg); try { Thread.sleep(3000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }; } 主线程代码执行完毕后,执行r,可是却不执行handleMessage()。
例4,由于handler属于主线程,handler.post(r)并非单独开启一条新线程,它只是执行r 线程的run()方法,在run()方法里有个while()致使循环执行,因为handler和这个run()方法的操做同属一条线程,因此只有run()执行完毕,才会执行handleMessage()。例4想要执行handleMessage()方法,去掉run()方法的while()循环便可。