从源码角度看Handler原理

在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();}期待遇上一位撑着油纸伞,结着忧愁丁香一样的姑娘;或者在春暖花开时,

从源码角度看Handler原理

相关文章:

你感兴趣的文章:

标签云: