本文主要是介绍Android之Handler与多线程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
声明: 本人菜鸟一枚, 本博客是本人自学的内容, 适用于初学者, 不喜勿喷, 谢谢大家
- Handler介绍
- Handler常用API
- Handle内部实现原理
- Handler内存泄漏问题分析
Handler介绍
对于像我这样的菜鸟来说, 刚开始学Android的时候, 如果想要实现类似下载的功能, 可能会这样写:
public void downloadClick(View view) {new Thread(new Runnable() {@Overridepublic void run() {//模拟下载try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}//下载完成后的操作textView.setText("下载完成");}}).start();}
这样写带来的后果是: 崩了
错误日志
android.view.ViewRootImpl$CalledFromWrongThreadException:
Only the original thread that created a view
对于熟悉Android开发的人看来是非常可笑的事情, 因为在多线程操作时我们忽略了两点:
- 不允许阻塞UI线程(主线程)
- 不能在UI线程之外访问Android UI工具包
以上是Android开发不可逾越的红线, 必须遵守.
但是我们还需要在子线程和主线程之间传递数据, 该怎么办呢? 那就得用我们的Handler
Handler常用API
Handler可以完成下述两点工作:
- 消息调度和将来的某个时间点执行一个Runnable
- 多个任务加入到一个队列中
对于刚才的代码我们可以这样改
private Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what){case 1:textView.setText("下载成功");break;}}};public void downloadClick(View view) {new Thread(new Runnable() {@Overridepublic void run() {//模拟下载try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}handler.sendEmptyMessage(1);}}).start();}
列举一下常用的API
handler.sendEmptyMessage(1);//发送空消息,
Message msg = handler.obtainMessage(); //从全局的消息池中返回一个Message对象
msg.what = 2;//设置标记
handler.sendMessage(msg);
handler.sendEmptyMessageAtTime(3, System.currentTimeMillis() + 3000);//表示在3s后发送一个空消息
handler.sendEmptyMessageDelayed(4, 3000); //含义同时, 延迟发送消息
//其他的都大同小异, 就不一一列举了
Handle内部实现原理
Handler实现机制:
1. Message对象, 表示要传递的一个消息, 内部使用数据结构实现消息池, 用于重复利用, 避免大量创建消息对象, 造成内存浪费
2. MessageQueue对象, 存放消息对象的消息队列, 先进先出原则
3. Looper对象负责管理当前线程的消息队列(MessageQueue), 用于循环检查消息队列, 从消息队列中一个一个的取出消息对象, 传入handlerMessage() 方法中
4. Handler对象负责把消息push到消息队列中, 以及接收并处理Looper从消息队列中取出的消息
图示说明:
Android启动程序时会在UI线程创建一个MessageQueue
Handler内存泄漏问题分析
如果我们仔细看我们之前写得程序在创建handler处有个黄色的叹号, 将详细信息调出来会是下面的样子
这就引出了我们所说的Handler的内存泄漏问题
到底哪儿出了问题呢??
大家仔细想想我们学习Java的时候, 在讲内部类的时候会讲到, 当我们创建一个内部类对象时, 我们的内部类对象默认会依附于外部类对象的存在而存在. 所以大家试想下面的例子:
handler.postDelayed(new Runnable() {@Overridepublic void run() {System.out.println("Test");}
}, 1000*60*5);
finish();
在这种情况下,当执行完了postDelayed方法之后当前的Activity会立即finsh(), 但是大家要想到此时我们的handler是依附于外部类的 , 所以此时的Activity并没有真正的关掉
问题的解决
1. 定义一个内部类时会默认拥有外部类对象的引用, 所以最好我们定义一个静态的内部类
2. 使用弱引用, 即使用 引用的强弱分为: 强引用 => 软引用 => 弱引用 ,如果实在不清楚之间的关系请直接百度一下
private MyHandler myHandler= new MyHandler(this);private static class MyHandler extends Handler{WeakReference<HandlerMemoryActivity> weakReference;public MyHandler(HandlerMemoryActivity activity) {weakReference = new WeakReference<HandlerMemoryActivity>(activity);}@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);HandlerMemoryActivity activity = weakReference.get();if (activity != null){//这里写对Activity的操作}}}
座右铭: 少说话, 多做事
这篇关于Android之Handler与多线程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!