Android 下载模块,使用Xutils3 的下载功能,Activity和services数据交互,listview显示下载进度
来源:互联网 发布:mac电脑重装系统 编辑:程序博客网 时间:2024/05/16 09:12
临近过年,今天将花了两天时间写的下载模块贡献出来,以前我也是天天需要什么功能,就天天查百度,现在自己也能开源一点东西了,也是非常很开心的,hahaha。
离职前写了音乐播放器的音乐下载界面,自己封装了下载线程,并使用多线程断点续传下载音乐,感觉多线程下载音乐也并不比单线程下载快多少,就一个4M的音乐来说,开3条线程下了46s,单线程下了60s,如果同时现在3个音乐,那么多线程下载相当于开了9 个线程,速度尽然和单线程的速度持平,有时候还会慢于3条线程,于是我放弃了多线程断点续传,还是老老实实写单线程的吧(- -!我觉得应该是我的下载线程的毛病,哈哈)。。。
于是今天就用了xutils3的网络访问模块,实现的需求是。
1、APP关闭后(kill),重新开启时,能记录当前下载进度,断点续传。
2、音乐能增删,暂停,显示下载速度和下载进度。
其实都写好了哈,主要说说编码思路。
通过Acitivity的bindService,可以调用service的bind来传递需要下载的文件信息到service,service通过调用xutils的带进度的下载模块,来回调下载信息,同时service通过下载观察者不断观察下载进度,将进度传递给Activity,之后setAdapter即可。
里面最主要的东西就是DownloadService,所有的代码逻辑都是这个类处理的。
传递下载文件信息的类MainActivity
这个类有个问题,
就是文件名的获取是根据Url倒叙截取/后面的文件来命名的,如果你的url不符合规则,请自行定义。
private String getfileName(String url) {//根据下载地址给下载文件命名 try{ return url.substring(url.lastIndexOf("/") + 1); }catch (Exception ex){ return mBinder.getCurrentListSize()+"";//返回一个数字 } }
权限问题
代码中加了6.0的动态权限判断,因为要操作SD卡,所以这里也要注意。
因为我没有6.0的测试手机,所以这里虽然都写了,但是只是作为提示使用,需要你自己更改逻辑位置,如果是6.0以下的,并没有问题的 。
Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 0: Toast.makeText(getBaseContext(),"已获取SD卡权限",Toast.LENGTH_SHORT).show(); //6.0系统在这里进行service的初始化 break; case 1: Toast.makeText(getBaseContext(),"SD卡权限未开启",Toast.LENGTH_SHORT).show(); break; } } }; //判断权限方法 private void initCheckSelfPermission() { //判断是否有内存卡权限 CheckSelfPermission.getSDCard(this); } //动态权限回调 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); doNext(requestCode,grantResults); } //动态权限回调,yes和no点击 private void doNext(int requestCode, int[] grantResults) { if (requestCode == DownLoadConstant.WRITE_EXTERNAL_STORAGE_REQUEST_CODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { LogUtils.d("权限获取成功"); handler.sendEmptyMessage(0); } else { handler.sendEmptyMessage(1); } } }
最关键的是DownloadService ,bind里有对外提供的增删改查方法
在下载的过程中,有缓存GetFileSharePreance 不断在保存下载的urls下载地址列表和文件下载进度,为APP下次重启提供断点,里面有详细注释。
/** * 作者:朱亮 on 2017/1/17 15:36 * 邮箱:171422696@qq.com * 下载服务类,执行下载任务,并将进度传递到Activity中(这里用一句话描述这个方法的作用) */public class DownloadService extends Service { public static final String ACTION_START = "ACTION_START"; public static final String ACTION_STOP = "ACTION_STOP"; public static final String ACTION_DELETE = "ACTION_DELETE"; private List<OnDownLoadBackListener> loadBackListeners = new ArrayList<OnDownLoadBackListener>();//注册一个下载观察者 private static final int DOWNLOADSERVICEID = 1;//下载监听传递值 private FileInfo fileInfo;//下载对象 private MyBinder myBinder = new MyBinder(); private ArrayList<FileInfo> mCurretList;//当前服务中的正在下载列表 private ArrayList<FileInfo> mCurretListOut;//输出的下载列表 private GetFileSharePreance preance; private HashMap<Integer,DownloanThread> map;//创建动态对象 @Override public IBinder onBind(Intent intent) { return myBinder; } @Override public void onCreate() { mCurretList = new ArrayList<>(); mCurretListOut = new ArrayList<>(); map = new HashMap<Integer,DownloanThread>(); preance = BaseApplication.getFileSharePreance();//获取缓存实例,这里的缓存主要用在APP关闭后,重新进入下载列表后显示使用 super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { // 获得Activity穿来的参数 fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo"); if (ACTION_START.equals(intent.getAction())) { startDownLoad(fileInfo);//开始下载 } else if (ACTION_STOP.equals(intent.getAction())) { stopDownLoad(fileInfo);//停止下载 } else if (ACTION_DELETE.equals(intent.getAction())) { deleteDownLoad(fileInfo);//删除下载 } } return super.onStartCommand(intent, flags, startId); } //开始下载逻辑处理方法 private void startDownLoad(FileInfo fileInfo) { if (fileInfo != null && !TextUtils.isEmpty(fileInfo.getUrl())) { preance.setUrlList(mCurretList);//从缓存地址集合中移除这一条(保存最新的地址集合) map.put(fileInfo.getId(),new DownloanThread()); map.get(fileInfo.getId()).Download(fileInfo);//开始下载 SPUtils.setLong(getApplicationContext(), SPKey.CURRENTLIST_SIZE, fileInfo.getId());//设置下载ID自增 sendHandler(); } } //停止下载逻辑处理方法 private void stopDownLoad(FileInfo fileInfo) { if (fileInfo != null && !TextUtils.isEmpty(fileInfo.getUrl())) { if (map.get(fileInfo.getId()) != null) { map.get(fileInfo.getId()).downLoadCancel();//下载线程停止 } sendHandler(); } } //删除下载逻辑处理方法 private void deleteDownLoad(FileInfo fileInfo) { if (fileInfo != null && !TextUtils.isEmpty(fileInfo.getUrl())) { for (int x = 0; x < mCurretList.size(); x++) {//如果是正在下载的列表,先暂停下载。 if (mCurretList.get(x).getUrl().equals(fileInfo.getUrl())) {//如果匹配到了 preance.delete(mCurretList.get(x).getUrl());//删除下载缓存 if(map.get(fileInfo.getId()) != null){ map.get(fileInfo.getId()).downLoadCancel();//从下载线程停止 } mCurretList.remove(mCurretList.get(x));//从下载列表移除这条 preance.setUrlList(mCurretList);//从缓存地址集合中移除这一条(保存最新的地址集合) preance.delete(fileInfo.getUrl());//删除缓存数据 } } sendHandler(); } } public class MyBinder extends Binder { //注册一个下载观察者 public void registDownLoadListener(OnDownLoadBackListener loadBackListener) { loadBackListeners.add(loadBackListener); } //取消一个观察者 public void unregistDownLoadListener(OnDownLoadBackListener loadBackListener) { loadBackListeners.remove(loadBackListener); } //设置当前的下载列表(会清空当前的下载列表哦,慎用,如果需要请用 appendToCurrentList()) public void setCurrentList(ArrayList<FileInfo> list) { mCurretList.clear(); if (list != null) { mCurretList.addAll(list); } } //获取当前的正在下载的所有下载信息列表 public ArrayList<FileInfo> getCurrentList() { return mCurretList; } //从缓存中获取下载信息 public ArrayList<FileInfo> getCurrentListFShareP(){ ArrayList<FileInfo> infos = new ArrayList<>(); ArrayList<String> list = preance.getUrlList();//先获取下载url集合 for(int x = 0 ; x < list.size() ; x++){//根据url地址查询下载的缓存数据 infos.add(preance.getFilePre(list.get(x))); } setCurrentList(infos); return infos; } //下载次数自增 public int getCurrentListSize() { long l = SPUtils.getLong(getApplicationContext(), SPKey.CURRENTLIST_SIZE); return (int) l + 1; } //添加当前的下载列表(相同下载地址文件过滤) public void appendToCurrentList(FileInfo info) { if (info != null) { // 只添加当前下载列表中没有的 boolean existed = false; for (int j = 0; j < mCurretList.size(); j++) { if ((mCurretList.get(j).getUrl()).equals(info.getUrl())) { existed = true; } } if (!existed) { mCurretList.add(info); startDownLoad(info);//开始下载 } } } //停止下载 public void stopDownLoad(FileInfo fileInfo) { if (fileInfo != null && !TextUtils.isEmpty(fileInfo.getUrl())) { stopDownLoad(fileInfo); } } //删除当前的某一个列表 public void deleyeCurrentList(FileInfo fileInfo) { deleteDownLoad(fileInfo); } //删除所有的下载列表信息(未编写) public void deleteAll(){ } } private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case DOWNLOADSERVICEID: for (int x = 0; x < loadBackListeners.size(); x++) {//有多少个界面在观察下载数据 mCurretListOut.clear(); for(int j = 0 ; j < mCurretList.size() ;j++){//正在下载列表中的数据 if(map.get(mCurretList.get(j).getId()) == null){//假如下载线程没有开启 mCurretListOut.add(mCurretList.get(j)); }else {//从下载线程中取数据 mCurretListOut.add(map.get(mCurretList.get(j).getId()).getFileInfo()); } } loadBackListeners.get(x).onDownloadSize(mCurretListOut);//传递给不同的观察者 } //当下载的时候,延迟不断执行这句话,让所有的观察者不至于失去下载的各种信息,这里控制视图更新频率 handler.sendEmptyMessageDelayed( DOWNLOADSERVICEID, 1000); break; default: super.handleMessage(msg); } } }; //发送hanlde private void sendHandler(){ if (!handler.hasMessages(DOWNLOADSERVICEID)) {//如果hanlde的观察者没有了,重新发送一个 handler.sendEmptyMessage(DOWNLOADSERVICEID); } }}
下载的实际类DownloanThread,名字看起来是个线程,其实不是,只是将实际下载类分离出来,调用xutils的下载方法和取消下载方法,提供一个获取下载文件详细信息方法。
//获取下载中的文件信息 public FileInfo getFileInfo(){ return new FileInfo(fileInfo.getId(),fileInfo.getUrl(),fileInfo.getFileName(),length,downlenth,downType); }
在这里回调文件的下载信息
cancelable = x.http().get(params, new Callback.ProgressCallback<File>() { @Override public void onWaiting() { LogUtils.e("等待中..."); downType = 0; } @Override public void onStarted() { LogUtils.e("开始下载。。。"); downType = 1; } @Override public void onLoading(long total, long current, boolean isDownloading) { LogUtils.e("tital = "+total + " current = "+current + " isDownLoading = "+isDownloading); length = (int) total; downlenth = (int) current; downType = 2; preance.update(new FileInfo(info.getId(),info.getUrl(),info.getFileName(),(int)total,(int)current,downType)); } @Override public void onSuccess(File result) { LogUtils.e("下载成功");//在这里下载成功的数据写进数据库里即可(已下载界面的数据从这里来的,哈哈,那个界面自己写) downType = 3; } @Override public void onError(Throwable ex, boolean isOnCallback) { LogUtils.e("下载失败"); downType = 4; } @Override public void onCancelled(CancelledException cex) { LogUtils.e("下载取消"); downType = 5; } @Override public void onFinished() { LogUtils.e("下载完成"); } });
最后在Adapter可以根据downType来显示下载过程中的状态了
已下载的界面没有写代码,偷个懒,请自己写哈
源码下载
- Android 下载模块,使用Xutils3 的下载功能,Activity和services数据交互,listview显示下载进度
- Python3使用requests模块显示下载进度
- Python3使用requests模块显示下载进度
- Python3使用requests模块显示下载进度
- Android xUtils3的使用及下载地址
- Android xUtils3下载文件的使用
- 使用Xutils3.0 进行上传和下载数据
- Android xUtils3 文件下载
- Android开发 下载显示进度
- Android开发 下载显示进度
- Android okhttputils显示下载进度
- 使用libcurl显示下载进度
- 文件下载通告栏显示下载进度和下载文件名称
- xutils3.0下载器的使用
- NSURLConnection下载显示进度
- python3 显示下载进度
- okhttputils显示下载进度
- Android中使用Notification实现应用更新显示下载进度
- 为什么一定要弄框架
- Java之对象转型
- ReactNative菜鸟备忘录(个人备忘)
- Ubuntu下“Tensorflow”的安装:
- codeforces 455 D. Serega and Fun (分块+双向链表)
- Android 下载模块,使用Xutils3 的下载功能,Activity和services数据交互,listview显示下载进度
- 行内元素与块级元素的区别,行内块级元素在IE8-的兼容性
- 安卓测试基础入门——ADB命令
- 元素的隐藏和显示(v-show指令)
- 关于js的&&和||的一些小用法,帮助阅读源码
- 我就是怕你学不会配色,所以..
- PAT乙级(Basic Level)真题1001
- 水循环过程与水文过程概念
- 网络请求图片