Android中的AsyncTask(异步任务)和接口回调使用详解

本文详细介绍了Android中的AsyncTask,它适用于UI线程的短作业,提供了一种辅助异步处理的方式,允许在后台执行操作并在UI上发布结果。同时,文章还探讨了接口回调的概念,以及它们在实际使用案例中的结合应用。在第四部分,作者深入讲解了如何自定义AsyncTask类并实现异步任务。

一、AsyncTask简单介绍

官方文档中对AsyncTask的解释是:AsyncTask更加适用于UI线程。这个类允许执行后台操作并在UI界面上发布结果,而不必处理多线程。AsyncTask是围绕Thread和Handler设计的一个辅助类,它不构成一个通用的线程框架。Asynctasks应该用于短作业(最多几秒钟)。

说的简单一点,AsyncTask其实就是Android提供的一个轻量级异步类。使用的时候可以自己自定义一个类去继承AsyncTask,就能在自定义类中实现异步操作,并且该类的实现方法中提供了接口来反馈当前异步任务执行的程度,最后还可以将执行的结果传递给UI线程。

二、接口回调简单介绍

接口回调,字面意思可以理解为定义一个接口,等以后出现了某一种状况的时候,然后去调用接口的方法做一些事。 多个比方说,我是搞开发的,目前手里没有项目,我就打电话奥巴马问他手里有没有项目给我做,要是他手里有项目就直接给我了,要是没有他会说后面可能有,你留下电话,有了我就打电话告诉你,这就是一个简单的回调理解,奥巴马后面打电话给我就相当于一个回调过程,而我打电话给奥巴马就相当于注册接口。 在Demo中,接口回调使用在异步任务执行完毕之后。因为你备份完短信可能要谈个吐司,播个音乐什么的,那就必须让MainActivity知道你已经执行完任务了,但是MainActivity怎么知道你已经执行完了,这里就需要接口回调了,让MainActivity实现接口,并且先定义好当完成任务需要做什么事情。这样当任务执行完就会直接调用MainActivity中定义好的方法更新UI等操作。短信备份操作回调结构图如下:

 

三、AsyncTask和接口回调的使用案例

先来看一下使用AsyncTask显示备份短信和还原短信的进度条。实现的原理很简单,写一个短信的工具类,在类中提供从 数据库 读取短信到集合和还原保存的短信到集合的方。我们自定义两个类继承AsyncTask,一个类实现将集合中的短信保存到本地的逻辑,另一个类实现将将集合中的短信插入到数据库中的逻辑。并且当异步任务执行完毕之后,我们使用接口回调,让主线程去处理短信备份和还原完成的工作,这里是谈吐司,当然你也可以播放音乐什么的。

 

四、AsyncTask使用详解

官方文档中称:异步任务将耗时操作放在后台线程上计算运行,然后将其结果在用户界面线程上发布。一个异步任务是由参数,过程和结果这3个泛型类型定义。它还包括四个步骤:oPostExecute,doInBackground,onProgressUpdate和onPostexecute。使用AsyncTask必须定义一个类继承AsyncTask,然后子类中必须实现doInBackground方法,经常也会实现oPostExecute方法。

自定义类继承AsyncTask代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<code> private class DownloadFilesTask extends AsyncTask<url, 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" );
     }
  }
</url,></code>

开启异步任务代码如下:

?
1
2
<code><code> new DownloadFilesTask().execute(url1, url2, url3);
</code></code>

1. 三个泛型类型

Params:参数。启动任务执行需要输入的参数,比如HTTP请求的URL Progress:过程。后台任务执行的百分比

Result:结果。后台执行任务最终返回的结果,比如String

这三个参数对四个步骤的方法的参数类型和返回值分别进行约束,如果没有约束的话,参数类型都为Void

?
1
2
<code><code><code> private class MyTask extends AsyncTask< void , void = "" > { ... }
</ void ,></code></code></code>

2. 四个步骤

onPreExecute()

调用时机:第一个执行,并且在异步任务开始之前调用 执行线程:主线程 方法参数:无 方法返回值:无

方法的作用:用于提醒用户,当前正在请求数据,一般用来弹出进度对话框

?
1
2
3
4
5
6
7
8
9
<code><code><code><code> @Override
protected void onPreExecute() {
     super .onPreExecute();
     // 运行在前台,初始化UI操作
     mDialog = new ProgressDialog(context);
     mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
     mDialog.show();
}
</code></code></code></code>

doInBackground()

调用时机:在onPreExecute方法执行完毕之后,这个方法一定会执行 执行线程:子线程

方法参数

由类上面的第一个泛型Params来限定 从execute方法里面传递进来

方法返回值

由类上面的第三个泛型Result来限定 将被当做onPostExecute()方法的参数

方法的作用:在后台线程当中执行耗时操作,比如联网请求数据。在执行过程中可以调用publicProgress()来更新任务的进度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<code><code><code><code><code> @Override
protected Boolean doInBackground(Void... params) {
 
     List<smsbean> list = SmsUtil.getAllSms(context);
 
     try {
         // 序列化器
         XmlSerializer xs = Xml.newSerializer();
         File file = new File(context.getFilesDir(), "sms.xml" );
         // 设置输出路径
         xs.setOutput( new FileOutputStream(file), "utf-8" );
 
         xs.startDocument( "utf-8" , true );
 
         xs.startTag( null , "smss" );
 
         for ( int i = 0 ; i < list.size(); i++) {
 
             SmsBean bean = list.get(i);
 
             xs.startTag( null , "sms" );
 
             xs.startTag( null , "address" );
             xs.text(bean.address);
             xs.endTag( null , "address" );
 
             xs.startTag( null , "date" );
             xs.text(bean.date + "" );
             xs.endTag( null , "date" );
 
             xs.startTag( null , "type" );
             xs.text(bean.type + "" );
             xs.endTag( null , "type" );
 
             xs.startTag( null , "body" );
             xs.text(bean.body);
             xs.endTag( null , "body" );
 
             xs.endTag( null , "sms" );
 
             SystemClock.sleep( 100 );
 
             publishProgress(i + 1 , list.size());
         }
 
         xs.endTag( null , "smss" );
         xs.endDocument();
 
         return true ;
     } catch (Exception e) {
         e.printStackTrace();
         return false ;
     }
}
</smsbean></code></code></code></code></code>

onProgressUpdate()

调用时机:在publishProgress()方法执行之后调用 执行线程:主线程

方法参数

由类上面的第二个泛型来限定。 参数是从publishProgress 传递进来 方法返回值:无

方法的作用:更新进度条

?
1
2
3
4
5
6
7
8
<code><code><code><code><code><code> @Override
protected void onProgressUpdate(Integer... values) {
     super .onProgressUpdate(values);
     // 更新UI
     mDialog.setMax(values[ 1 ]);
     mDialog.setProgress(values[ 0 ]);
}  
</code></code></code></code></code></code>

onPostExecute()

调用时机:在doInBackground 执行完毕之后调用 执行线程:主线程

方法参数

由类上面的第三个泛型来限定。 doInBackground的返回值就是这个方法的参数

方法返回值:无

方法的作用:相当于Handler的handleMessage()方法,在这里面可以对doInBackground()方法得到的结果进行处理,更新UI

1
2
3
4
5
6
7
8
9
10
11
<code><code><code><code><code><code><code> @Override
protected void onPostExecute(Boolean result) {
     super .onPostExecute(result);
     if (result) {
         listener.onSuccess();
     } else {
         listener.onFailure();
     }
     mDialog.dismiss();
}
</code></code></code></code></code></code></code>

3. 需要遵守的准则

任务必须在主线程中执行 任务对象必须在主线程中构建 execute方法必须在主线程中执行 四个步骤中的方法不能直接调用,publicProgress()方法可以在类中暴露一个方法出去,让外边调用

任务只能执行一次

1.6开始的时候,可以并发执行多个任务,但是3.0之后,只能允许单个任务执行。如果真的想要多任务并发执行,那么可以运行在自己的线程池里面

?
1
2
<code><code><code><code><code><code><code><code>mTask.executeOnExecutor(exec, params)
</code></code></code></code></code></code></code></code>

五、接口回调简单使用

使用接口回调,一般有以下四个步骤,通过这四个步骤就能形成一个简单的回调。在Android中很多地方都用到了接口回调,比如控件的点击事件,GitHub上的许多开源框架也都用了接口回调,开发过程了也频频涉及到接口回调,所以这是一个很重要的知识点。

定义接口,可以是内部接口,也可以是自定义接口

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<code><code><code><code><code><code><code><code><code> /**
  * 定义回调接口
  */
public interface OnTaskListener{
 
     /**
      * 成功之后调用这个方法
      */
     void onSuccess();
 
     /**
      * 失败之后调用这个方法
      */
     void onFailed();
 
 
}
</code></code></code></code></code></code></code></code></code>

接收接口实现类对象

?
1
2
3
4
5
<code><code><code><code><code><code><code><code><code><code> public BackupTask(Context context, OnTaskListener listener) {
         mContext = context;
         mListener = listener;
}
</code></code></code></code></code></code></code></code></code></code>

通过接口实现类对象,访问对应的方法

?
1
2
3
4
5
6
7
8
<code><code><code><code><code><code><code><code><code><code><code> if (result){
     mListener.onSuccess();
     // == ToastUtil.showShort(mContext,"备份成功");
} else {
     mListener.onFailed();
     // == ToastUtil.showShort(mContext,"备份失败");
}
</code></code></code></code></code></code></code></code></code></code></code>

在实现中编写调用方法执行操作的代码

?
1
2
3
4
5
6
7
8
9
10
11
12
<code><code><code><code><code><code><code><code><code><code><code><code> // 直接调用工具类的回调方法来弹出吐司
new SmsUtil().backUpSms( this , new SmsUtil.OnTaskListener() {
     @Override
     public void onSuccess() {
         ToastUtil.showShort(MainActivity. this , "备份成功" );
     }
 
     @Override
     public void onFailure() {
         ToastUtil.showShort(MainActivity. this , "备份失败" );
     }
});</code></code></code></code></code></code></code></code></code></code></code></code>







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值