Android之Handler与多线程
2016-07-06 22:53
513 查看
声明: 本人菜鸟一枚, 本博客是本人自学的内容, 适用于初学者, 不喜勿喷, 谢谢大家
Handler介绍
Handler常用API
Handle内部实现原理
Handler内存泄漏问题分析
这样写带来的后果是: 崩了
错误日志
对于熟悉Android开发的人看来是非常可笑的事情, 因为在多线程操作时我们忽略了两点:
不允许阻塞UI线程(主线程)
不能在UI线程之外访问Android UI工具包
以上是Android开发不可逾越的红线, 必须遵守.
但是我们还需要在子线程和主线程之间传递数据, 该怎么办呢? 那就得用我们的Handler
消息调度和将来的某个时间点执行一个Runnable
多个任务加入到一个队列中
对于刚才的代码我们可以这样改
列举一下常用的API
1. Message对象, 表示要传递的一个消息, 内部使用数据结构实现消息池, 用于重复利用, 避免大量创建消息对象, 造成内存浪费
2. MessageQueue对象, 存放消息对象的消息队列, 先进先出原则
3. Looper对象负责管理当前线程的消息队列(MessageQueue), 用于循环检查消息队列, 从消息队列中一个一个的取出消息对象, 传入handlerMessage() 方法中
4. Handler对象负责把消息push到消息队列中, 以及接收并处理Looper从消息队列中取出的消息
图示说明:
Android启动程序时会在UI线程创建一个MessageQueue
这就引出了我们所说的Handler的内存泄漏问题
到底哪儿出了问题呢??
大家仔细想想我们学习Java的时候, 在讲内部类的时候会讲到, 当我们创建一个内部类对象时, 我们的内部类对象默认会依附于外部类对象的存在而存在. 所以大家试想下面的例子:
在这种情况下,当执行完了postDelayed方法之后当前的Activity会立即finsh(), 但是大家要想到此时我们的handler是依附于外部类的 , 所以此时的Activity并没有真正的关掉
问题的解决
1. 定义一个内部类时会默认拥有外部类对象的引用, 所以最好我们定义一个静态的内部类
2. 使用弱引用, 即使用 引用的强弱分为: 强引用 => 软引用 => 弱引用 ,如果实在不清楚之间的关系请直接百度一下
座右铭: 少说话, 多做事
Handler介绍
Handler常用API
Handle内部实现原理
Handler内存泄漏问题分析
Handler介绍
对于像我这样的菜鸟来说, 刚开始学Android的时候, 如果想要实现类似下载的功能, 可能会这样写:public void downloadClick(View view) { new Thread(new Runnable() { @Override public 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(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 1: textView.setText("下载成功"); break; } } }; public void downloadClick(View view) { new Thread(new Runnable() { @Override public 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() { @Override public 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); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); HandlerMemoryActivity activity = weakReference.get(); if (activity != null){ //这里写对Activity的操作 } } }
座右铭: 少说话, 多做事
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories