在Android中,有一个规定就是除了主线程,其他线程不能操作UI视图,因为不这样做的话会出现线程不安全问题。但还有一个规定UI线程在执行一个操作如果5秒内没有响应就会包ANR错误。所以UI线程中不允许访问网络这样的耗时操作,那么问题来了,子线程执行耗时操作,比如从网络获取图片,但子线程不能更新UI,而主线程能更新UI,但不能去下载图片。这样handler消息处理机制就出现了。
1. Handler是什么?
handler是Android给我们提供用来更新UI的一套机制,也是一套消息处理的机制,我们可以发送消息,也可以通过它处理消息。
2. 为什么要使用Handler?
Android在设计时,就封装了一套消息消息创建、传递、处理机制,如果不遵循这样的机制就没办法更新UI,就会抛出异常。
3. Android中为什么要设计只能通过Handler机制更新UI?
解决多线程并发问题。如果允许多线程更新UI会导致界面错乱,如果非要使用多线程并使用加锁机制更新UI又会导致性能下降,所以更新UI的操作全部交给主线程。
4.那么handler机制是怎样的机制呢?
了解handler机制,首先需要清楚四个核心类: Message:对发送的消息的封装 MessageQueue:消息队列,存放所有的消息 Looper:可以循环读取消息(从MessageQueue中读取) Handler:处理消息,同时也是发送消息的
具体来看看handler是怎么实现的。
4.1使用1:主线程接收子线程发来的消息(下载图片为例) 1)在主线程中初始化handler对象:
private Handler handler = new Handler(){(Message msg) {//处理子线程发送过来的messageBitmap bitmap = (Bitmap)msg.obj;imageView.setImageBitmap(bitmap);}};
2)然后子线程中下载好图片后发送图片给主线程:
new Thread(new Runnable() {@Override() {HttpGet get = new HttpGet(path);HttpClient client = new DefaultHttpClient();HttpResponse response = null;try {response = client.execute(get);if (response.getStatusLine().getStatusCode() == 200) {byte[] arr = EntityUtils.toByteArray(response.getEntity());Bitmap bitmap = BitmapFactory.decodeByteArray(arr, 0,arr.length);// 下载完成时把图片发送给主线程// 从MessageQueue中获取可用的Message对象,如果没有可用的Message对象则会创建一个新的Message对象Message msg = Message.obtain();// 把发送的图片封装到msg中msg.obj = bitmap;// 使用Handler发送msghandler.sendMessage(msg);// 把msg发送给实例化handler的线程}} catch (Exception e) {e.printStackTrace();}}}).start();
消息的拦截:
/** * 拦截消息测试 * @author Administrator * */{Handler handler = new Handler(new Callback() {(Message msg) {Log.i(“–“, “消息都要经过我这里”);;}}) {(Message msg) {super.handleMessage(msg);Log.i(“–“, “我才是处理消息的”);}};(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);new Thread(new Runnable() {() {handler.sendEmptyMessage(1);}}).start();}}
3)使用1有关handler机制的操作有: Handler handler = new Handler(); handleMessage(Message msg);
Message msg = Message.obtain(); handler.sendMessage(msg);
那么现在来看一看它内部到底是怎样执行的。
5.从源码一步一步分析handler原理
5.1Handler handler = new Handler();
public Handler() {this(null, false);}
这个无参构造方法会调用两个参数的构造方法,注意上面的参数null和false,如下:
public Handler(Callback callback, boolean async) {if (FIND_POTENTIAL_LEAKS) {final Class<? extends Handler> klass = getClass();if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&(klass.getModifiers() & Modifier.STATIC) == 0) {Log.w(TAG, “The following Handler class should be static or leaks might occur: ” +klass.getCanonicalName());}}mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException(“Can’t create handler inside thread that has not called Looper.prepare()”);}mQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;}
那来看看这个两个参数的构造方法都做了些什么。 FIND_POTENTIAL_LEAKS这个变量初始化为false private static final boolean FIND_POTENTIAL_LEAKS = false; 所以直接执行后面的,也就是这些:
mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException(“Can’t create handler inside thread that has not called Looper.prepare()”);}mQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;
这几句的操作就是得到一个Looper对象和一个MessageQueue对象,mLooper = Looper.myLooper();中Looper.myLooper()方法中是得到当前线程的Looper对象。那么当前线程是什么?在这里,因为我们是在主线程中实例化Handler对象,所以当前线程就是主线程,值得注意的是,主线程在创建时就会维护一个Looper对象和MessageQueue对象,所以这里得到的Looper对象和消息队列都是主线程的。
public static Looper myLooper() {return sThreadLocal.get();}期待遇上一位撑着油纸伞,结着忧愁丁香一样的姑娘;或者在春暖花开时,