Android(6)——Handler,异步任务

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)
在这里插入图片描述

  1. 异步下载文件更新进度条
    下载,读写权限,AndroidManifest.xml:
    在这里插入图片描述
    DownloadActivity.java:主线程–> start
    点击按键
    发起下载
    开启子线程做下载
    下载过程中通知主线程 --> 主线程更新进度条
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 倒计时的实现
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  3. 用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

  1. 网络上请求数据:申请网络权限,读写存储权限
    在这里插入图片描述
  2. 设计界面,布局layout
    ProgressBar,Button,TextView
    AsyncTask.java
    在这里插入图片描述
  3. 下载前,UI
    在这里插入图片描述
  4. 下载中,数据
    在另外一个线程中处理数据
    在这里插入图片描述
  5. 下载后,UI
    在这里插入图片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章