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.this, “下载完成”, 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的代码,去做相应的修改。
- 下一次我们如果要下载别的东西,按照我们前面的代码,我们又要重新复制一份,这样无疑是做了很多重复的工作。
说到这样,我相信大多数人的第一感觉就是把AsyncTask提取为外部类,封装起来。是的,确实,我们就是要把AsyncTask提取为外部类。那提取为歪不累之后呢?我们要访问Activity里面的空间,要怎样访问呢?
-
在Activity里面定义静态方法
-
把需要访问的View对象通过构造函数传递进来
-
采用接口回调机制
前面说到的三种方法,是可以做到AsyncTask与外界进行通讯的。但第一第二中方法明显不行。原因如下:
-
第一种方法定义静态方法,那View对象也必须定义为static变量,这static变量的级别比较高,不易被垃圾回收机制回收,易发生没存泄露。
-
第二种方法,把需要访问的View对象通过构造函数传递进来。如果需要访问的对象少的话,勉强可以接受,如果多的话,那岂不是要定义很多成员变量。不过最致命的还算是代码耦合性太高了。还不如AsyncTask直接作为内部类。
好了,说了这么多,下面我们一起来看怎样使用接口回调机制来进行解耦。
AsyncTask 使用接口回调机制来进行解耦
- 使用接口回调机制,首先我们必须有一个接口
public interface DownloadListener {
void onStart();
void onProgress(FileInfo fileInfo);
void onFinish(FileInfo FileInfo);
void onPaused(FileInfo fileInfo);
void onCancled();
}
- 将DownLoadTask提取为一个外部类,并将需要传递的参数传递进来
public class DownloadTask extends AsyncTask<Void,FileInfo,FileInfo> {
private String mDownloadUrl;
private final String mDstPath;
private final String mFileName;
private final DownloadListener mDownloadListener;
public DownloadTask(String downloadUrl, String dstPath, String fileName, DownloadListener downloadListener){
mDownloadUrl = downloadUrl;
mDstPath = dstPath;
mFileName = fileName;
mDownloadListener = downloadListener;
}
}
- 在相应的地方调用我们接口的方法
public class DownloadTask extends AsyncTask<Void,FileInfo,FileInfo> {
@Override
protected void onPreExecute() {
super.onPreExecute();
mDownloadListener.onStart();
}
@Override
protected FileInfo doInBackground(Void… params) {
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();
return fileInfo;
}
@Override
protected void onProgressUpdate(FileInfo… values) {
super.onProgressUpdate(values);
mDownloadListener.onProgress(values[0]);
}
@Override
protected void onPostExecute(FileInfo fileInfo) {
super.onPostExecute(fileInfo);
mDownloadListener.onFinish(fileInfo);
}
@Override
protected void onCancelled() {
super.onCancelled();
mDownloadListener.onCancled();
}
}
使用
以后我们要下载东西,只需要调用下面的方法即可。同时,如果产品再更改需求,比如,从显示一个进度条ProgressDialog对话框,改成显示一个ProgressBar,我们只需要在
onProgress()里面做相应的修改就好了,在也不用去阅读DownloadTask里面的代码呢?减少了代码的耦合性,是不是瞬间感觉世界很美好呢?
mDownloadTask = new DownloadTask(mDownloadUrl, mDstPath, null, new
DownloadListener() {
@Override
public void onStart() {
start();
}
@Override
public void onProgress(FileInfo fileInfo) {
refreshProgress(fileInfo);
}
@Override
public void onFinish(FileInfo fileInfo) {
downloadfinish(fileInfo);
}
@Override
public void onPaused(FileInfo fileInfo) {
}
@Override
public void onCancled() {
}
});
mDownloadTask.execute();
AsyncTask使用的注意事项
-
The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
-
The task instance must be created on the UI thread.(AsyncTask必须在UI 线程里面初始化
-
execute(Params…) must be invoked on the UI thread.
-
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params…), onProgressUpdate(Progress…) manually.(不要手动地调用 onPreExecute(), onPostExecute(Result), doInBackground(Params…), onProgressUpdate(Progress…) 这些方法)
-
The task can be executed only once (an exception will be thrown if a second execution is attempted.) (Task任务只能被执行一次,否则会抛出异常)
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/cf2f67daec506ba75c0f4cdaa2d9f89f.jpeg)
总结
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的14套腾讯、字节跳动、阿里、百度等2021最新面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!**
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/cf2f67daec506ba75c0f4cdaa2d9f89f.jpeg)
总结
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的14套腾讯、字节跳动、阿里、百度等2021最新面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。
[外链图片转存中…(img-c0XfwQ0K-1713296253455)]
[外链图片转存中…(img-g3w6YHhw-1713296253456)]
[外链图片转存中…(img-I3grdVph-1713296253457)]
[外链图片转存中…(img-HXXBJOwM-1713296253457)]
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!