文章目录
Android
安卓开发者指南:https://developer.android.google.cn/guide
1 Handler
1.1 概念
Handler:消息分发对象,进行发送和处理消息,并且其Runable对象和一个线程的MessageQueue关联。
为什么要使用Handler:解决子线程如何通知UI组件更新的问题,实现了不同线程间通信的一种机制。消息调度,将一个任务切换到某个指定的线程中去执行。多个线程并发更新UI的同时,保证线程安全。
通信机制
Handler机制的核心类:
1.Handler:作用就是发送与处理信息,如果希望Handler正常工作,在当前线程中要有一个Looper对象;
2.Looper类:为一个线程开启一个消息循环。通过MessageQueue来存放消息和事件,一个线程只能有一个 Looper,对应一个MessageQueue。Looper.prepare(),Looper.loop()(注意,写在Looper.loop之后的代码不会被执行,这个函数内部是一个循环)
3.Message:Handler接收与处理的消息对象
4.MessageQueue:消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueue;
UI线程:就是主线程,系统在创建UI线程的时候会初始化一个Looper对象,同时也会创建一个与其关联的MessageQueue。
1.2 Handler使用
相关方法:
void handleMessage(Message msg):处理消息的方法,通常是用于被重写
sendEmptyMessage(int what):发送空消息
sendEmptyMessageDelayed(int what,long delayMillis):指定延时多少毫秒后发送空信息
sendMessage(Message msg):立即发送信息
sendMessageDelayed(Message msg):指定延时多少毫秒后发送信息
final boolean hasMessage(int what):检查消息队列中是否包含what属性为指定值的消息 如果是参数为(int what,Object object):除了判断what属性,还需要判断Object属性是否为指定对象的消息
方式一: post(Runnable)
创建一个工作线程,实现 Runnable 接口,实现 run 方法,处理耗时操作;
创建一个 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();
方式二: sendMessage(Message)
创建一个工作线程,继承 Thread,重新 run 方法,处理耗时操作;
创建一个 Message 对象,设置 what 标志及数据
通过 sendMessage 进行投递消息
创建一个handler,重写 handleMessage 方法,根据 msg.what 信息判断,接收对应的信息,再在这里更新 UI。
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) { //判断标志位
case 1:
/**
获取数据,更新UI
*/
break;
}
}
};
public class WorkThread extends Thread {
@Override
public void run() {
super.run();
/**
耗时操作
*/
//从全局池中返回一个message实例,避免多次创建message(如new Message)
Message msg =Message.obtain();
msg.obj = data;
msg.what=1; //标志消息的标志
handler.sendMessage(msg);
}
}
new WorkThread().start();
1.3 Handler 存在的问题
1.UI线程/主线程/ActivityThread
2.线程不安全
3.消息循环机制:Looper
内存方面
Handler 被作为 Activity 引用,如果为非静态内部类,则会引用外部类对象。当 Activity finish 时,Handler可能并未执行完,从而引起 Activity 的内存泄漏。故而在所有调用 Handler 的地方,都用静态内部类。
异常方面
当 Activity finish 时,在 onDestroy 方法中释放了一些资源。此时 Handler 执行到 handlerMessage 方法,但相关资源已经被释放,从而引起空指针的异常。
避免
如果是使用 handlerMessage,则在方法中加try catch。
如果是用 post 方法,则在Runnable方法中加try catch。
Handler 的改进
内存方面:使用静态内部类创建 handler 对象,且对 Activity 持有弱引用。
异常方面:不加 try catch,而是在 onDestory 中把消息队列 MessageQueue 中的消息给 remove 掉。
作者:空心散人
链接:https://www.jianshu.com/p/0a274564a4b1
来源:简书
1.4 Handler实践的三种效果
应用场景:
1.To schedule messages and runnables to be executed as some point in the future
2.To enqueue an action to be performed on a different thread than your own.
创建Handler,重写方法handleMessage(Message msg)
UI线程做轻量级操作
1.Handler. sendMessage()
2.Handler.post()
3.handleMessage(Message msg)
- 异步下载文件更新进度条
下载,读写权限,AndroidManifest.xml:
DownloadActivity.java:主线程–> start
点击按键
发起下载
开启子线程做下载
下载过程中通知主线程 --> 主线程更新进度条
- 倒计时的实现
- 用Handler来实现简单打地鼠游戏
< ImageView>、< Button>、< TextView>
Activity实现View.OnClickListener接口,initView(),重写方法onClick();二维数组模拟随机座标
2 异步任务
2.1 AsyncTask
异步,相当于多个线程,同时进行
多线程提高效率
ANR(Application Not Responding)应用程序无响应,由多线程引起的事件。
1.Main/UI Thread和Worker Thread
2. Main/UI Thread和Worker Thread之间的通信
3. Thread / Runnable线程安全
4.普通的主线程更新
Activity.runOnUiThread(Runpable)
View.post(Runnable)
View.postDelayed(Runnable, long)
异步加载实现方式:AsyncTask,多线程或者线程池
AsyncTask好处:封装并简化了异步操作,方便后台线程操作后更新UI,实现了Thread和Handler的封装,实质:Handler异步消息处理机制
常用方法:
1.泛型参数: <Params,Progress,Result>
2. UI操作 onPreExecute执行前 操作前准备工作,onPostExecute执行后在主线程中 执行结果处理
3.后台线程操作doInBackground执行中执行耗时操作
4.输入输出Params, Result
5.进度显示onProgressUpdate,收到进度然后处理,也是在UI线程中
6.取消onCancelled(Boolean aBoolean)、onCancelled()
2.2 网络下载demo
- 网络上请求数据:申请网络权限,读写存储权限
- 设计界面,布局layout
ProgressBar,Button,TextView
AsyncTask.java
- 下载前,UI
- 下载中,数据
在另外一个线程中处理数据
- 下载后,UI