AsyncTask 使用及封装实践,头条android面试算法

  • AsyncTask的简单使用

  • AsyncTask的封装使用

  • AsyncTask使用注意事项


AsyncTask的使用例子


简介

AsyncTask ,异步任务。没错,就想字面上理解的那样。它允许我们在子线程执行耗时任务,在UI 线程更新操作(如更新进度条等)。简单来说,就是帮我们做好了子线程与UI 线程的通讯,我们只需要调用响应的方法实现即可。底层是用Handler消息机制实现的。

在Android开发中,我们经常需要下载各种东西,为了给用户较好的体验,我们经常需要显示下载进度。今天我们用以这个为例子,来教大家怎样使用AsyncTak。当然,github上面有很多开源库,实现断点下载,文件重命名等。不过这些不是本篇博客的重点。

效果图

AsyncTask的主要几个方法

  • Void onPreExecute()

在task 任务开始执行的时候调用,在doInBackground(Params… params)方法之前调用,在主线程中执行

- Result doInBackground(Params… params)

主要用来执行耗时操作,在子线程中执行,Params为我们参数的类型。而Result这个泛型,是我们返回的类型(可以是Integer,Long,String等等类型,只要不是八种基本类型就OK),同时 Result 的类型将作为 onPostExecute(Result result)的参数。

  • Void onProgressUpdate(Progress… values)

Runs on the UI thread after publishProgress(Progress…) is invoked. 当我们调用 publishProgress()方法的时候,会调用 onProgressUpdate()这个方法

  • Void onPostExecute(Result result)

在doInBackground()方法执行完毕之后,会调用这个方法,是在主线程中执行的。但如果我们手动调用了cancelled()方法,那么这个方法将不会被调用。

  • void onCancelled()

在Task 任务取消的时候会调用

  • execute(Params… params)

Executes the task with the specified parameters.当我们调用这个方法的时候,会执行任务

  • executeOnExecutor(Executor exec, Params… params)

在指定的线程池里面执行Task

需要注意的是,Params,Progress,Result 并不是一种特定的类型,它其实是泛型,它支持除了八种基本类型之外的类型,跟普通的泛型一样。

AsyncTask使用的几个步骤

这里我们以下载一个apk为例讲解

  1. 写一个类继承AsyncTask,并传入Params,Progress,Result 。三个参数的类型。

比如我们传入的 Params,Progress,Result 的参数的类型分别为 Void, FileInfo, FileInfo,那我们可以这样写。

private class MyDownloadTask extends AsyncTask<Void, FileInfo, FileInfo>{

}

那Void, FileInfo, FileInfo,这几个参数的类型在哪里体现出来呢?

请看下面注释

private class MyDownloadTask extends AsyncTask<Void, FileInfo, FileInfo> {


// 方法参数的类型为Void,跟我们传入的Void一致,返回类型为 FileInfo ,跟我们传入Result的类型FileInfo一致

@Override

protected FileInfo doInBackground(Void… params) {

}

// 方法参数类型为FileInfo,跟我们传入Progress的类型FileInfo一致

@Override

protected void onProgressUpdate(FileInfo… values) {

}

// 方法参数FileInfo,跟我们传入Result的类型FileInfo一致

@Override

protected void onPostExecute(FileInfo fileInfo) {

}

}

  1. 如果我们更新进度的话,需要重写 onProgressUpdate()方法,并在doInBackground()方法里面调用publishProgress()方法

protected FileInfo doInBackground(Void… params) {

publishProgress(fileInfo);

}

@Override

protected void onProgressUpdate(FileInfo… values) {

super.onProgressUpdate(values);

refreshProgress(values[0]);

}

  1. 当我们调用execute(Params… params) 或者 executeOnExecutor(Executor exec, Params… params) 方法的时候,Task将被防盗相应的 Executor 执行。

MyDownloadTask myDownloadTask = new MyDownloadTask(mDownloadUrl, mDstPath);

myDownloadTask.execute();

完整的Task代码如下

private class MyDownloadTask extends AsyncTask<Void, FileInfo, FileInfo> {

String mDownLoadUrl;

String mDstPath;

public MyDownloadTask(String downloadUrl, String dstPath) {

this.mDownLoadUrl = downloadUrl;

this.mDstPath = dstPath;

}

@Override

protected void onPreExecute() {

super.onPreExecute();

start();

}

@Override

protected FileInfo doInBackground(Void… params) {

//url字符串,检查网址是否已http:// 开头

mDownLoadUrl = (mDownLoadUrl.startsWith(“http://”)) ? mDownLoadUrl : “http://” +

mDownLoadUrl;

Log.d(TAG, “doInBackground: mDownLoadUrl=” + mDownLoadUrl);

Log.d(TAG, “doInBackground: mDstPath=” + mDstPath);

URL url = null;

FileInfo fileInfo = null;

int contentLength = -1;

int downloadLength = 0;

OutputStream output = null;

InputStream istream = null;

try {

url = new URL(mDownLoadUrl);

//打开到url的连接

HttpURLConnection connection = (HttpURLConnection) url.openConnection();

contentLength = connection.getContentLength();

Log.i(TAG, “doInBackground: contentLength=” + contentLength);

//O部分,大体来说就是先检查文件夹是否存在,不存在则创建

istream = connection.getInputStream();

String filename = mDownLoadUrl.substring(mDownLoadUrl.lastIndexOf("/") + 1);

File dir = new File(mDstPath);

if (!dir.exists()) {

dir.mkdir();

}

File file = new File(mDstPath + filename);

// 如果存在同名文件,重命名

if (file.exists()) {

file = FileUtils.rename(file.getPath());

}

output = new FileOutputStream(file);

byte[] buffer = new byte[1024 * 4];

int count = 0;

int len = -1;

while ((len = istream.read(buffer)) != -1) {

output.write(buffer, 0, len);

downloadLength += len;

if (count == 10) {

fileInfo = new FileInfo(contentLength, downloadLength, file, file.getPath

(), file.getName());

publishProgress(fileInfo);

count = 0;

}

count++;

}

// 有可能count还没有走到10

fileInfo = new FileInfo(contentLength, downloadLength, file, file.getPath(), file

.getName());

publishProgress(fileInfo);

output.flush();

output.close();

istream.close();

} catch (Exception e) {

e.printStackTrace();

try {

IOUtils.close(output);

IOUtils.close(istream);

} catch (IOException e1) {

e1.printStackTrace();

}

} finally {

try {

IOUtils.close(output);

IOUtils.close(istream);

} catch (IOException e1) {

e1.printStackTrace();

}

}

return fileInfo;

}

@Override

protected void onProgressUpdate(FileInfo… values) {

super.onProgressUpdate(values);

refreshProgress(values[0]);

}

@Override

protected void onPostExecute(FileInfo fileInfo) {

super.onPostExecute(fileInfo);

downloadfinish(fileInfo);

}

@Override

protected void onCancelled() {

super.onCancelled();

}

}

private void start() {

mTvDownloadText.setText(“开始下载”);

mProgressBar.setMax(100);

mProgressBar.setProgress(0);

}

private void downloadfinish(FileInfo fileInfo) {

Log.i(TAG, “onPostExecute: 下载完成=” + fileInfo.mPath);

Toast.makeText(MainActivity.thi

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

浏览器打开:qq.cn.hn/FTe 免费领取

s, “下载完成”, Toast.LENGTH_SHORT).show();

}

private void refreshProgress(FileInfo value) {

FileInfo fileInfo = value;

if (fileInfo != null) {

mProgressBar.setMax((int) fileInfo.mLength);

mProgressBar.setProgress((int) fileInfo.mDownloadLength);

mDownText = fileInfo.mFile.getName() + “下载了” + fileInfo.mDownloadLength + “总长度是” +

fileInfo.mLength;

mTvDownloadText.setText(mDownText);

}

}


AsyncTask的封装使用


前面我们讲完了AsyncTask的基本使用,不知道你有没有发现,其实代码耦合性是挺高的,

- 我们直接在 onProgressUpdata(),onPostExecute()方法里面更新我们的界面,即我们的AsyncTask访问了我们Activity里面的控件,那如果我们修改了Activity的控件,我们岂不是又要去阅读AsyncTask的代码,去做相应的修改。

- 下一次我们如果要下载别的东西,按照我们前面的代码,我们又要重新复制一份,这样无疑是做了很多重复的工作。
ileInfo.mLength);

mProgressBar.setProgress((int) fileInfo.mDownloadLength);

mDownText = fileInfo.mFile.getName() + “下载了” + fileInfo.mDownloadLength + “总长度是” +

fileInfo.mLength;

mTvDownloadText.setText(mDownText);

}

}


AsyncTask的封装使用


前面我们讲完了AsyncTask的基本使用,不知道你有没有发现,其实代码耦合性是挺高的,

- 我们直接在 onProgressUpdata(),onPostExecute()方法里面更新我们的界面,即我们的AsyncTask访问了我们Activity里面的控件,那如果我们修改了Activity的控件,我们岂不是又要去阅读AsyncTask的代码,去做相应的修改。

- 下一次我们如果要下载别的东西,按照我们前面的代码,我们又要重新复制一份,这样无疑是做了很多重复的工作。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值