1、几个相关概念简述:java
一、MessageQueue: 消息队列,存放消息的容器。注意:每个线程最多只有一个MessageQueue,建立一个线程的时候,并不会自动建立其MessageQueue。一般使用一个Looper对象对该线程的MessageQueue进行管理。主线程建立时,会建立一 个默认的Looper对象,而Looper对象的建立,将自动建立一个MessageQueue。其余非主线程,不会自动建立Looper,要须要的时候,经过调用prepare函数来实现。android
二、Message:消息对象,存储与MessageQueue中,一个MessageQueue包含多个Message对象,这些Message对象遵循先进先出的原则。注意:一般会new一个message实例对象,或者经过Handler对象的obtainMessage()获取一个Message实例,使用removeMessages()方法能够将消息从队列中删除;数据结构
三、Looper:消息封装的载体,是MessageQueue的管理者。每个MessageQueue都不能脱离Looper而存在,Looper对象的建立是经过prepare函数来实现的。同时每个Looper对象和一个线程关联。经过调用Looper.myLooper()能够得到当前线程的Looper对象。注意:建立一个Looper对象时,会同时建立一个MessageQueue对象。除了主线程有默认的Looper,其余线程默认是没有MessageQueue对象的,因此,不能接受Message。如须要接受,本身定义一个Looper对象(经过prepare函数),这样该线程就有了本身的Looper对象和MessageQueue数据结构了。多线程
四、Handler:封装了消息的发送和处理,handler负责将须要传递的信息封装成Message,经过调用handler对象的obtainMessage()来实现; 将消息传递给Looper,这是经过handler对象的sendMessage()来实现的。继而由Looper将Message放入MessageQueue中。 当Looper对象看到MessageQueue中含有Message,就将其广播出去。该handler对象收到该消息后,调用相应的handler对象的handleMessage()方法 对其进行处理。并发
五、HandlerThread:本质上是线程加消息的实现;ide
总结:handler负责发送消息,Looper负责接收handler发送的消息,并直接把消息回传给handler本身,MessageQueue是消息存储的容器。函数
2、Handler机制:oop
一、Handler是什么?post
FAQ:handler是android提供用来更新UI的一套机制,也是一套消息处理的机制,咱们能够发送消息,也能够经过它处理消息;性能
二、为何要使用Handler?
FAQ:android设计的时候就封装了一套消息建立、传递处理的机制,若是不遵循这样的机制就没法更新UI,就会抛出异常。
三、如何使用Handler?
FAQ:见Handler经常使用方法,sendMessage,sendMessageDelayed,post(Runnable),postDelayed(Runnable, long)等。
四、android设计为何只能经过Handler机制更新UI呢?
FAQ:根本目的是解决多线程并发的问题,加锁会致使性能降低;
五、常见的handler异常分析。
(1)android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views。
这个问题主要是在子线程里修改了UI致使的,
(2)Can't create handler inside thread that has not called
这个问题是在子线程里建立Handler前没有调用Looper.prepare()和looper关联致使的。
六、如何实现一个与线程相关的Handler?
FAQ:下面代码实现了在子线程里建立Handler对象。
class MyThread extends Thread { public Handler handler; @Override public void run() { Looper.prepare();//没有这段代码会报5中的(2)异常。 handler = new Handler() { @Override public void handleMessage(Message msg) { System.out.println("currentThread------------->" + Thread.currentThread().getId()); } }; Looper.loop(); } }
七、如何在主线程给子线程发送消息?
FAQ:见下面代码,实现了主线程和子线程互发信息。
public class MainActivity extends Activity implements OnClickListener { private TextView textView; private Button start, stop; private Handler thread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_main); textView = (TextView) findViewById(R.id.textView1); start = (Button) findViewById(R.id.Start); stop = (Button) findViewById(R.id.Stop); start.setOnClickListener(this); stop.setOnClickListener(this); HandlerThread handlerThread = new HandlerThread("handlerThread"); handlerThread.start(); thread = new Handler(handlerThread.getLooper()) { @Override public void handleMessage(Message msg) { Message message = new Message(); mainHandler.sendMessageDelayed(message, 1000); System.out.println("threadHandler---->" + Thread.currentThread().getId()); } }; } // 主线程 Handler mainHandler = new Handler() { public void handleMessage(Message msg) { Message message = new Message(); thread.sendMessageDelayed(message, 1000); System.out.println("mainHandler---->" + Thread.currentThread().getId()); }; }; @Override public void onClick(View v) { if (v == start) { mainHandler.sendEmptyMessage(0); } else if (v == stop) { mainHandler.removeMessages(0); } } }
八、Android中更新UI有几种方式?
FAQ:常见android中更新UI的方式又如下四种,runOnUIThread ,handler.post ,handler.sendMessage view.post。经过源码去看,实质上都是使用handler机制去处理UI的。
九、android非UI线程真的不能更新UI吗?
FAQ:在android非UI现场中真的不能更新UI吗,你们看下下面的代码:
new Thread(){ public void run() { textView.setText("updateview"); }; }.start();
运行这段代码,你会神奇地发现更新了UI,再看下面的这段代码:
new Thread(){ public void run() { try{ Thread.sleep(2000); textView.setText("updateview"); }catch(Exception e){ } }; }.start();
你会神奇地发现报了“五、常见的handler异常分析”中的异常(1),因此不建议在非UI线程中去更新UI。
十、Handler的Callback用法:
private Handler handler = new Handler(new Callback() {//截获消息 @Override public boolean handleMessage(Message msg) { Toast.makeText(getApplicationContext(), "1", 1).show(); return false;//false会发送两个消息,true,不会处理下面的消息 } }) { @Override public void handleMessage(Message msg) { Toast.makeText(getApplicationContext(), "2", 1).show(); } }; handler.sendEmptyMessage(0);