标签:span control each none sample script 常用 amp extern
为什么是更好的Android多线程下载框架呢,原因你懂的,广告法嘛!
本篇我们我们就来聊聊多线程下载框架,先聊聊我们框架的特点:
下面我们在说下该框架能实现那些的应用场景:
该项目的雏形始于14年的公司项目需要用到多线程下载,但当时实现的单线程多任务断点续传,后面不断完善,在这之间遇到过很多坑,也对一个下载框架有了更深的认识,所以在16年又重写了该框架。
项目的Github地址:https://github.com/lifengsofts/AndroidDownloader
项目的官网地址:http://i.woblog.cn/AndroidDownloader
项目还处于发展状态,但已经趋于稳定,并且有一定的编码规范,同时采用了多个开源项目的质量控制方案以保证每次代码提交的可靠性。
下面上几张框架Demo的截图,这样用户在心中有一个自己的概念,但是推荐各位还是讲Demo下载到本地亲自,运行一下。
第一个界面是单独下载一个文件。
第二个界面是应用中最常用的一个界面,该界面来自业务数据。
第三个页面是离线管理中的下载中的界面。
第四个页面是离线管理中的下载完成的界面。
可以看到他们在每个界面都能暂停下载,继续下载,以及删除,并且都能拿到进度,状态等信息。
下面就来看看这么强大的下载框架那该如何来使用呢?
我相信这一步任何一个项目都已经添加了,但是还是不得不提一下。
该框架需要网络访问权限,如果你是讲文件下载到存储卡,那相应的需要添加存储卡访问权限。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
因为该框架采用才service中下载一个文件的。这样做的目的是下载任务一般都需要在后头下载,如果在Activity中来做这类任务,我想任何一个新手都知道这样不行。
<service android:name="cn.woblog.android.downloader.DownloadService">
<intent-filter>
<action android:name="cn.woblog.android.downloader.DOWNLOAD_SERVICE" />
</intent-filter>
</service>
我们提供了多种集成方式,比如:gradle,maven,jar。选择适合你自己的就行了。
在module目录下面的build.gradle文件中添加如下内容:
compile ‘cn.woblog.android:downloader:1.0.1‘
或者你使用的Maven依赖管理工具。那道理其实是一样的,在pom文件中添加:
<dependency>
<groupId>cn.woblog.android</groupId>
<artifactId>downloader</artifactId>
<version>1.0.0</version>
</dependency>
或者你也可以参考该链接使用Snapshots版本。
如果你的项目使用了混淆规则,那么一定要加上。
-keep public class * implements cn.woblog.android.downloader.db.DownloadDBController
-keep class cn.woblog.android.downloader.domain.** { *; }
现在万事俱备只欠东风了,接下来只需要创建一个下载管理器,该框架所有的操作都是通过该来实现的:
downloadManager = DownloadService.getDownloadManager(context.getApplicationContext());
或者你可以使用更详细的来配置该框架:
Config config = new Config();
//set database path.
// config.setDatabaseName("/sdcard/a/d.db");
// config.setDownloadDBController(dbController);
//set download quantity at the same time.
config.setDownloadThread(3);
//set each download info thread number
config.setEachDownloadThread(2);
// set connect timeout,unit millisecond
config.setConnectTimeout(10000);
// set read data timeout,unit millisecond
config.setReadTimeout(10000);
downloadManager = DownloadService.getDownloadManager(this.getApplicationContext(), config);
//create download info set download uri and save path.
final DownloadInfo downloadInfo = new DownloadInfo.Builder().setUrl("http://example.com/a.apk")
.setPath("/sdcard/a.apk")
.build();
//set download callback.
downloadInfo.setDownloadListener(new DownloadListener() {
@Override
public void onStart() {
tv_download_info.setText("Prepare downloading");
}
@Override
public void onWaited() {
tv_download_info.setText("Waiting");
bt_download_button.setText("Pause");
}
@Override
public void onPaused() {
bt_download_button.setText("Continue");
tv_download_info.setText("Paused");
}
@Override
public void onDownloading(long progress, long size) {
tv_download_info
.setText(FileUtil.formatFileSize(progress) + "/" + FileUtil
.formatFileSize(size));
bt_download_button.setText("Pause");
}
@Override
public void onRemoved() {
bt_download_button.setText("Download");
tv_download_info.setText("");
downloadInfo = null;
}
@Override
public void onDownloadSuccess() {
bt_download_button.setText("Delete");
tv_download_info.setText("Download success");
}
@Override
public void onDownloadFailed(DownloadException e) {
e.printStackTrace();
tv_download_info.setText("Download fail:" + e.getMessage());
}
});
//submit download info to download manager.
downloadManager.download(downloadInfo);
下载一个文件时直接创建一个DownloadInfo,然后设置下载链接和下载路径。再添加一个监听。就可以提交到下载框架了。
通过下载监听器我们可以获取到很多状态。开始下载,等待中,暂停完成,下载中,删除成功,下载成功,下载失败等状态。
我们这里演示如何在RecyclerView这类列表控件使用。当然如果你用的是ListView那道理是一样的。
class ViewHolder extends RecyclerView.ViewHolder {
private final ImageView iv_icon;
private final TextView tv_size;
private final TextView tv_status;
private final ProgressBar pb;
private final TextView tv_name;
private final Button bt_action;
private DownloadInfo downloadInfo;
public ViewHolder(View view) {
super(view);
iv_icon = (ImageView) view.findViewById(R.id.iv_icon);
tv_size = (TextView) view.findViewById(R.id.tv_size);
tv_status = (TextView) view.findViewById(R.id.tv_status);
pb = (ProgressBar) view.findViewById(R.id.pb);
tv_name = (TextView) view.findViewById(R.id.tv_name);
bt_action = (Button) view.findViewById(R.id.bt_action);
}
@SuppressWarnings("unchecked")
public void bindData(final MyDownloadInfo data, int position, final Context context) {
Glide.with(context).load(data.getIcon()).into(iv_icon);
tv_name.setText(data.getName());
// Get download task status
downloadInfo = downloadManager.getDownloadById(data.getUrl().hashCode());
// Set a download listener
if (downloadInfo != null) {
downloadInfo
.setDownloadListener(new MyDownloadListener(new SoftReference(ViewHolder.this)) {
// Call interval about one second
@Override
public void onRefresh() {
if (getUserTag() != null && getUserTag().get() != null) {
ViewHolder viewHolder = (ViewHolder) getUserTag().get();
viewHolder.refresh();
}
}
});
}
refresh();
// Download button
bt_action.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (downloadInfo != null) {
switch (downloadInfo.getStatus()) {
case DownloadInfo.STATUS_NONE:
case DownloadInfo.STATUS_PAUSED:
case DownloadInfo.STATUS_ERROR:
//resume downloadInfo
downloadManager.resume(downloadInfo);
break;
case DownloadInfo.STATUS_DOWNLOADING:
case DownloadInfo.STATUS_PREPARE_DOWNLOAD:
case STATUS_WAIT:
//pause downloadInfo
downloadManager.pause(downloadInfo);
break;
case DownloadInfo.STATUS_COMPLETED:
downloadManager.remove(downloadInfo);
break;
}
} else {
// Create new download task
File d = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "d");
if (!d.exists()) {
d.mkdirs();
}
String path = d.getAbsolutePath().concat("/").concat(data.getName());
downloadInfo = new Builder().setUrl(data.getUrl())
.setPath(path)
.build();
downloadInfo
.setDownloadListener(new