Handler:是一个消息分发对象,进行发送和处理消息,而且其 Runnable 对象与一个线程的 MessageQueue 关联。
做用:调度消息,将一个任务切换到某个指定的线程中去执行。git
倘若子线程容许访问 UI,则在多线程并发访问状况下,会使得 UI 控件处于不可预期的状态。
传统解决办法:加锁,但会使得UI访问逻辑变的复杂,其次下降 UI 访问的效率。github
采用单线程模型处理 UI 操做,经过 Handler 切换到 UI 线程,解决子线程中没法访问 UI 的问题。网络
建立一个 handler,经过 handler.post/postDelay,投递建立的 Runnable,在 run 方法中进行更新 UI 操做。多线程
new Thread(new Runnable() {
@Override
public void run() {并发
/** 耗时操做 */ handler.post(new Runnable() { @Override public void run() { /** 更新UI */ } });
}
}).start();ide
建立一个handler,重写 handleMessage 方法,根据 msg.what 信息判断,接收对应的信息,再在这里更新 UI。post
private Handler handler = new Handler(){this
@Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { //判断标志位 case 1: /** 获取数据,更新UI */ break; } }
};.net
public class WorkThread extends Thread {线程
@Override
public void run() { super.run(); /** 耗时操做 */
Message msg =Message.obtain(); //从全局池中返回一个message实例,避免屡次建立message(如new Message)
msg.obj = data;
msg.what=1; //标志消息的标志
handler.sendMessage(msg);
}
new WorkThread().start();
Handler 被做为 Activity 引用,若是为非静态内部类,则会引用外部类对象。当 Activity finish 时,Handler可能并未执行完,从而引发 Activity 的内存泄漏。故而在全部调用 Handler 的地方,都用静态内部类。
当 Activity finish 时,在 onDestroy 方法中释放了一些资源。此时 Handler 执行到 handlerMessage 方法,但相关资源已经被释放,从而引发空指针的异常。
避免
则使用以下方式建立 handler 对象:
/** 为避免handler形成的内存泄漏 一、使用静态的handler,对外部类不保持对象的引用 二、但Handler须要与Activity通讯,因此须要增长一个对Activity的弱引用 */ private static class MyHandler extends Handler { private final WeakReference<Activity> mActivityReference; MyHandler(Activity activity) { this.mActivityReference = new WeakReference<Activity>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); MainActivity activity = (MainActivity) mActivityReference.get(); //获取弱引用队列中的activity switch (msg.what) { //获取消息,更新UI case 1: byte[] data = (byte[]) msg.obj; activity.threadIv.setImageBitmap(activity.getBitmap(data)); break; } } }
并在 onDesotry 中销毁:
@Override protected void onDestroy() { super.onDestroy(); //避免activity销毁时,messageQueue中的消息未处理完;故此时应把对应的message给清除出队列 handler.removeCallbacks(postRunnable); //清除runnable对应的message //handler.removeMessage(what) 清除what对应的message }
public class MainActivity extends AppCompatActivity { ImageView threadIv; ImageView runnableIv; SendThread sendThread; PostRunnable postRunnable; private final MyHandler handler = new MyHandler(this); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); threadIv = (ImageView) findViewById(R.id.thread_iv); runnableIv = (ImageView) findViewById(R.id.runnable_iv); sendThread = new SendThread(handler); sendThread.start(); postRunnable = new PostRunnable(handler); postRunnable.setRefreshUI(new PostRunnable.RefreshUI() { @Override public void setImage(byte[] data) { runnableIv.setImageBitmap(getBitmap(data)); } }); new Thread(postRunnable).start(); } /** 为避免handler形成的内存泄漏 一、使用静态的handler,对外部类不保持对象的引用 二、但Handler须要与Activity通讯,因此须要增长一个对Activity的弱引用 / private static class MyHandler extends Handler { private final WeakReference<Activity> mActivityReference; MyHandler(Activity activity) { this.mActivityReference = new WeakReference<Activity>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); MainActivity activity = (MainActivity) mActivityReference.get(); //获取弱引用队列中的activity switch (msg.what) { //获取消息,更新UI case 1: byte[] data = (byte[]) msg.obj; activity.threadIv.setImageBitmap(activity.getBitmap(data)); break; } } } private Bitmap getBitmap(byte[] data) { return BitmapFactory.decodeByteArray(data, 0, data.length); } @Override protected void onDestroy() { super.onDestroy(); //避免activity销毁时,messageQueue中的消息未处理完;故此时应把对应的message给清除出队列 handler.removeCallbacks(postRunnable); //清除runnable对应的message //handler.removeMessage(what) 清除what对应的message } }
public class PostRunnable implements Runnable { private Handler handler; private RefreshUI refreshUI; byte[] data = null; public PostRunnable(Handler handler) { this.handler = handler; } @Override public void run() { /** 耗时操做 */ final Bitmap bitmap = null; HttpClient httpClient = new DefaultHttpClient(); HttpGet httpGet = new HttpGet("http://i3.17173cdn.com/2fhnvk/YWxqaGBf/cms3/FNsPLfbkmwgBgpl.jpg"); HttpResponse httpResponse = null; try { httpResponse = httpClient.execute(httpGet); if (httpResponse.getStatusLine().getStatusCode() == 200) { data = EntityUtils.toByteArray(httpResponse.getEntity()); } } catch (IOException e) { e.printStackTrace(); } //返回结果给UI线程 handler.post(new Runnable() { @Override public void run() { refreshUI.setImage(data); } }); } public interface RefreshUI { public void setImage(byte[] data); } public void setRefreshUI(RefreshUI refreshUI) { this.refreshUI = refreshUI; } }
public class SendThread extends Thread { private Handler handler; public SendThread(Handler handler) { this.handler = handler; } @Override public void run() { super.run(); /** 耗时操做 */ byte[]data=null; HttpClient httpClient = new DefaultHttpClient(); HttpGet httpGet = new HttpGet("https://d36lyudx79hk0a.cloudfront.net/p0/descr/pc27/3095587d8c4560d8.png"); HttpResponse httpResponse = null; try { httpResponse = httpClient.execute(httpGet); if(httpResponse.getStatusLine().getStatusCode()==200){ data= EntityUtils.toByteArray(httpResponse.getEntity()); } } catch (IOException e) { e.printStackTrace(); } //返回结果给UI线程 doTask(data); } /** 经过handler返回消息 @param data */ private void doTask(byte[] data) { Message msg =Message.obtain(); //从全局池中返回一个message实例,避免屡次建立message(如new Message) msg.obj = data; msg.what=1; //标志消息的标志 handler.sendMessage(msg); } }
本文发表于我的博客:http://lavnfan.github.io/,欢迎指教。