Android AsyncTask与Thread+Handler的分析

13 篇文章 0 订阅

Android AsyncTask与Thread+Handler的分析

基本概念

public abstract class AsyncTask
extends Object

java.lang.Object
android.os.AsyncTask<Params, Progress, Result>

通过AsyncTask,可以正确,轻松地使用UI线程。 此类允许您执行后台操作并在UI线程上发布结果,无需操纵threads and/or handlers。

AsyncTask被设计为围绕Thread和Handler的帮助类(其实就是对Thread和Handler的一种封装),并且不构成通用的线程框架。 理想情况下,应将AsyncTasks用于较短的操作(最多几秒钟)。如果需要使线程长时间运行,则强烈建议您使用java.util.concurrent包提供的各种API,例如 Executor,ThreadPoolExecutor和FutureTask。

异步任务由在后台线程上运行的计算定义,并且其结果发布在UI线程上。 异步任务由3个通用类型(Params,Progress和Result)以及4个步骤(四个按顺序执行的方法)(onPreExecute,doInBackground,onProgressUpdate和onPostExecute)。

用法

必须将AsyncTask子类化才能使用。 子类将覆盖至少一个方法(doInBackground(Params …)),并且通常将覆盖第二个方法(onPostExecute(Result)。)

示例如下:

 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

创建实例与运行:

new DownloadFilesTask().execute(url1, url2, url3);

通用参数解释

一个异步任务(AsyncTask)使用的三种通用参数如下:

  1. Params

    执行时发送给任务的参数类型

  2. Progress

    后台计算期间的进度单位类型

  3. Result

    后台计算结果类型

四个步骤(四个实现方法)

当执行异步任务时,该任务将顺序执行四个方法

  • onPreExecute()

    在执行任务(异步任务)之前在UI线程上调用。此步骤通常用于设置任务,例如,通过在用户界面中显示进度栏。

  • doInBackground(Params…)

    在执行任务之前在UI线程上调用。此步骤通常用于设置任务,例如,通过在用户界面中显示进度栏。
    doInBackground(Params …),在onPreExecute()完成执行后立即在后台线程上调用。此步骤用于执行可能需要很长时间的后台计算。异步任务的参数将传递到此步骤。计算结果必须通过此步骤返回,并将传递回最后一步。此步骤还可以使用publishProgress(Progress …)发布一个或多个进度单位。这些值在onProgressUpdate(Progress …)步骤中发布在UI线程上。

  • onProgressUpdate(Progress…)

    在调用publishProgress(Progress …)之后在UI线程上调用。执行的时间是不确定的。此方法用于在后台计算仍在执行时在用户界面中显示任何形式的进度。例如,它可用于为进度栏设置动画或在文本字段中显示日志。

  • onPostExecute(Result)

    在后台计算完成后在UI线程上调用。后台计算的结果作为参数传递到此方法。

缺陷

Android中提供了AsyncTask作为异步调用,并且Android强制规定如果有耗时操作(例如数据库交互,网络请求等)就必须在子线程中运行以免阻塞UI线程太久导致程序超时关闭同时也加强了用户体验。

但是我在使用AsyncTask的时候用于网络请求与服务器进行数据交互,发现了AsyncTask的缺点:

使用AsyncTask如果在doInBackground方法中调用网络请求但是请求一旦发送不会等请求执行完毕就会继续往下执行onPostExecute这样不能完成我想要的等待网络操作完成后再继续执行下一步。

此时我转用Thread+Handler进行网络交互。

使用方法:

  • 在UI线程中写一个继承(extends)Handler的内部类并重写handleMessage方法用于处理子线程返回的数据
// 先写n个Handler处理N个数据
class HomeHandler extends Handler{
   @Override
   public void handleMessage(@NonNull Message msg) {
      Bundle msgBundle;
      switch (msg.what){
         case Constant.GET_CRITERIA_MESSAGE:
            Log.e("msg","GET_CRITERIA_MESSAGE");
            msgBundle = msg.getData();
            // 处理返回数据更新UI
            break;
         case Constant.SAVE_MS_MESSAGE:
            Log.e("msg","SAVE_MS_MESSAGE");
            msgBundle = msg.getData();
            // 处理返回数据更新UI
            break;
         case Constant.CALCULATE_MESSAGE:
            Log.e("msg","CALCULATE_MESSAGE");
            msgBundle = msg.getData();
            // 处理返回数据更新UI
            break;
      }

   }
}
  • 创建子线程实现Runnable,需要Handler作为成员函数并且构造函数初始化时务必需要传递handler。在子线程中通过UI线程传过来的Handler在处理完耗时操作后进行消息返回
/**
 * Date: 2019/10/17
 * Author:Satsuki
 * Description:
 */
public class GetCriteriaThread implements Runnable {

   private Handler handler;

   public GetCriteriaThread() {
   }

   public GetCriteriaThread(Handler handler) {
      this.handler = handler;
   }

   @Override
   public void run() {
      Log.e("GetCriteriaThread","1");

      String url = “”;

      Message message = new Message();
      Bundle msgBundle = new Bundle();

      Log.e("url",url);
      // 把json字符串发回主线程,交给UI线程解决
      msgBundle.putString("criteriaResponse","网络请求获取的数据");
      // 设置从什么线程发送的Message
      message.what = Constant.GET_CRITERIA_MESSAGE;
      message.setData(msgBundle);
      handler.sendMessage(message);
//    Log.e("criteriaList",criteriaList.toString());
   }
}
  • 在主线程中创建执行
// 初始化Handler必须要在执行任务之前
HomeHandler homeHandler= new HomeHandler()
GetCriteriaThread getCriteriaThread = new GetCriteriaThread(homeHandler);
Thread asyncThread = new Thread(getCriteriaThread);
asyncThread.start();

执行后子线程发送的数据交给UI线程中的Handler处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值