Android类FileDownloadList分析
作者:hebedich 发布时间:2022-06-17 02:11:36
先上代码,再来分析
public class FileDownloadList {
/**上下文*/
private Context mContext;
/**请求对象*/
private BaseRequestLims fileRequest = null;
/**进度条对话框*/
private AlertDialog progressDialog = null;
/**进度条控件变量*/
private ProgressBar mProgress;
/**百分比显示控件*/
private TextView mProgressPercent;
private File localFile = null;
/**接收HttpHelper中获取到文件大小后发送的广播,确定文件大小*/
private DownLoadReceiver receiver;
/**文件大小*/
private long fileLength = -1L;
/**是否已注册广播标志*/
private boolean castFlag = false;
/**是否显示进度条标志*/
private boolean showDialog = false;
/**文件下载完的回调接口*/
private Runnable mCallback = null;
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int tempSize = (int)localFile.length();
if(tempSize < fileLength){
//文件下载中
if(showDialog){
//显示了进度条的情况下,更新进度条
int progress = (int)((Double.valueOf(tempSize) / Double.valueOf(fileLength)) * 100);
mProgress.setProgress(tempSize);
mProgressPercent.setText(progress + "%");
}
}else{
//下载文件完毕
if(castFlag){//如已注册广播,注销广播
mContext.unregisterReceiver(receiver);
castFlag = false;
}
if(showDialog){
mProgress.setProgress((int)fileLength);
mProgressPercent.setText("100%");
progressDialog.dismiss();
}
if(mCallback != null){
try{
Thread.sleep(500);
mCallback.run();
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
};
/**
* 构造器
* @param activity
*/
/**
* 构造器
* @param activity
* @param showDialog 显示进度条标志
*/
public FileDownloadList(Context context, boolean showDialog){
mContext = context;
this.showDialog = showDialog;
fileRequest = new BaseRequestLims(context,ClientServiceType.FILE_DOWN);
fileRequest.setMethodType(BaseRequestLims.METHOD_TYPE_POST);
fileRequest.setContext(mContext);
}
public BaseRequestLims getFileRequest(){
return fileRequest;
}
/**
* 通过关联类型来下载文件
* @param fileName 文件名称或文件在服务器上的相对路径加名称
* @param saveDir 保存在本地的文件目录
* @param saveName 保存在本地的文件名称
* @param gllx 关联类型
* @param callback 下载后的处理线程
*/
public void downloadFile(String fileName, String saveDir, String saveName, Runnable callback){
if(callback != null){
mCallback = callback;
}
File saveDirFile = new File(saveDir);
//judge the save dir path exist or not
if(!saveDirFile.exists()){
saveDirFile.mkdirs();
}
localFile = new File(saveDir,saveName);
if(localFile.isDirectory()){
new AlertDialog.Builder(mContext).setTitle("提示").setMessage("the save file is directory").show();
return;
}
if(fileRequest.getServiceType()==null){
fileRequest.setServiceType(ClientServiceType.FILE_DOWN);
}
fileRequest.addParameter("fpath", fileName);
fileRequest.addParameter("fname", saveName);
fileRequest.setStreamPath(localFile.getAbsolutePath());
fileRequest.setStream(true);
if(localFile.exists()){
if(localFile.length() == 0){
invokeFile(fileRequest);
}else{
//文件存在直接打开
if(showDialog)
buildProgressDialog().show();
mHandler.sendMessage(mHandler.obtainMessage());
}
}else{
invokeFile(fileRequest);
}
}
/**
* 进入文件下载子线程
* @param request
*/
private void invokeFile(final BaseRequestLims request){
try{
if(showDialog){
buildProgressDialog().show();
}
receiver = new DownLoadReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("SAVE_DOWNLOAD_FILE");
mContext.registerReceiver(receiver, filter);
castFlag = true;
//下载的子线程
new Thread(){
@Override
public void run() {
super.run();
HttpHelper.invoke(request);
}
}.start();
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* 创建进度对话框
* @return
*/
private AlertDialog buildProgressDialog(){
AlertDialog.Builder builder = new Builder(mContext);
builder.setTitle("正在下载文件,请稍候...");
RelativeLayout container = new RelativeLayout(mContext);
mProgress = new ProgressBar(mContext);
mProgress.setId("progress".hashCode());
BeanUtils.setFieldValue(mProgress, "mOnlyIndeterminate", Boolean.valueOf(false));
mProgress.setIndeterminate(false);
LayerDrawable layerDrawable = (LayerDrawable)mContext.getResources().getDrawable(android.R.drawable.progress_horizontal);
ClipDrawable clipDrawable = (ClipDrawable)layerDrawable.getDrawable(2);
clipDrawable.setColorFilter(Color.parseColor("#32B5E5"), Mode.SRC_IN);
mProgress.setProgressDrawable(layerDrawable);
mProgress.setPadding(0, 0, 0, 0);
mProgress.setIndeterminateDrawable(
mContext.getResources().getDrawable(android.R.drawable.progress_indeterminate_horizontal));
mProgressPercent = new TextView(mContext);
mProgressPercent.setId("percent".hashCode());
mProgressPercent.setText("0%");
mProgressPercent.setTextSize(18);
int containerPadding = DimensionUtils.dip2Px(mContext, 10);
container.setPadding(containerPadding, containerPadding, containerPadding, containerPadding);
LayoutParams progressLayoutParams = new LayoutParams(
LayoutParams.MATCH_PARENT, DimensionUtils.dip2Px(mContext, 4));
progressLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL);
progressLayoutParams.addRule(RelativeLayout.LEFT_OF, mProgressPercent.getId());
mProgress.setLayoutParams(progressLayoutParams);
LayoutParams percentLayoutParams = new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
percentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
percentLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL);
mProgressPercent.setLayoutParams(percentLayoutParams);
container.addView(mProgressPercent);
container.addView(mProgress);
builder.setView(container);
builder.setNegativeButton("取消", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
progressDialog = builder.create();
return progressDialog;
}
class DownLoadReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//显示进度条
fileLength = intent.getLongExtra("FILE_LENGTH", -1);
if(showDialog){
mProgress.setMax((int)fileLength);
}
//更新进度条的线程
new Thread(){
@Override
public void run() {
super.run();
while(true){
try{
Thread.sleep(500);
}catch (Exception e) {
e.printStackTrace();
}
mHandler.sendMessage(mHandler.obtainMessage());
//获取下载文件的大小
int loadedSize = (int)localFile.length();
if(loadedSize >= fileLength){
break;
}
}
}
}.start();
}
}
public DownLoadReceiver getReciver()
{
return receiver;
}
}
它的逻辑:
创建一个FileDownloadList对象后,就可以直接使用该下述方法来实现下载功能。
downloadFile(String fileName, String saveDir, String saveName, Runnable callback)
在实现上是这么个意思:
1.在当前上下文,开启下载线程。当获取到要下载的文件的大小时,发送一个广播过来(这部分没有展示在上述代码中)。
2.在当前上下文中,注册一个广播 * ,监听广播标识为SAVE_DOWNLOAD_FILE的广播。首次监听到发出来的广播后,首次发送过来的广播,包含了要下载的文件的大小信息,然后就每隔5毫秒检测本地文件的大小,直到本地文件的大小(loadedSize)大于等于要下载的文件(fileLength)大小时,退出该循环。
在不断检测的过程中,通过mHandler.sendMessage(mHandler.obtainMessage()); ,让UI线程更新进度条。
下载线程,会不断将服务器返回的数据流,写到本地文件中,所以,本地文件的大小会不断变化,直到,它的大小跟要下载的文件的大小相等时,就退出这个不断检测本地文件大小的线程。
其它没有在上述代码中表现出来的内容(在其它部分的代码中):
1.在invokeFile( final BaseRequestLims request)方法中,开了一个如下的下载线程.该下载线程,会将服务器返回的文件流,写到本地文件(localFile)中;然后,它还会发送一个标识为SAVE_DOWNLOAD广播,包含的信息有要下载文件的文件大小fileLength。
//下载的子线程
new Thread(){
@Override
public void run() {
super.run();
HttpHelper.invoke(request);
}
}.start();
上述代码存在的问题:
1.上下文,使用的是某个Activity,如果发生系统调用了该Activity的onDestroy()时,下载线程还没有完成,也就意味着,loadedSize的大小还是小于fileLength。从而,那个不断检测本地文件大小的线程就一直在执行着。
即是检测本地文件大小的线程和下载线程还在执行着:
检测本地文件大小的线程:
new Thread(){
@Override
public void run() {
super.run();
while(true){
try{
Thread.sleep(500);
}catch (Exception e) {
e.printStackTrace();
}
mHandler.sendMessage(mHandler.obtainMessage());
//获取下载文件的大小
int loadedSize = (int)localFile.length();
if(loadedSize >= fileLength){
break;
}
}
}
}.start();
下载线程:
new Thread(){
@Override
public void run() {
super.run();
HttpHelper.invoke(request);
}
}.start();
那么,会出现什么问题呢?
1).我可以确定的就是,mContext会出现泄漏。
2). DownLoadReceiver不能正常被取消注册。
分析,待续。
猜你喜欢
- 一、工具类代码public class TaskHelper {#region 多线程操作 &nbs
- 1、Nacos config springboot starter包我们在springboot应用中集成nacos配置中心时,添加了以下依赖
- 写在最前面上周零零碎碎花了一周的时间研究水印的开发,现在终于写了个入门级的Demo,做下笔记同时分享出来供大家参考。Demo是在我上次写的
- 本文为大家分享了java实现水果超市管理系统的具体代码,供大家参考,具体内容如下首先建立水果类的界面public class Fruit {
- 本文实例讲述了C#实现系统托盘通知的方法。分享给大家供大家参考。具体实现方法如下:namespace WindowsApplication1
- 前言今天是2021LOL全球总决赛,一直不被大家看好的EDG冲到了决赛对战韩国队的DK,可以说EDG面对如此强大的对手,想赢是比较难的,为了
- Java中有两种处理异常的方式,分别是用throws抛出异常、用try、catch捕获异常。try-catch在Javatry-catch语
- ApplicationContext简述ApplicationContext代表IOC容器,在SpringIOC容器中读取Bean配置创建B
- 大致思路:注解实现方式:就是用 反射机制. 获取指定的包下使用了注解的类,存储在一个map容器, 然后获取map容器下类的属性, 利用反射给
- Spring Boot 2.7.6整合redis与低版本的区别最近在写程序的时候参考了之前写过的一篇文章spring boot整合redis
- 前言在我们的日常企业应用开发当中,会碰到很多的图片素材访问的场景。比如社交类应用,您会在朋友圈中存放大量的图片,还有一些在线旅游或者直播的行
- 一. BigInteger类1. 简介在之前给大家讲解8种基本类型时就说过,不同的数据类型,有不同的取值范围,我们再通过下表回顾一下:类型所
- Nashorn是什么Nashorn,发音“nass-horn”,是德国二战时一个坦克的命名,同时也是java8新一代的javascript引
- SpringMVC注解@RequestMapping在之前的 hello world 示例中,用到了 @RequestMapping 注解,
- 1. 单个属性yaml 内的属性如下:server: port: 80只需在成员变量上注解 @Value(“
- 前提:当我们使用Winform开发的时候,经常会遇到:System.InvalidOperationException:&ldquo
- 本文实例为大家分享了Swing拆分窗格控件JSplitPane的使用方法,供大家参考,具体内容如下package day1115;impor
- 目前很多网页都有滑动验证,目的就是防止不良爬虫扒他们网站的数据,我这次本着学习的目的使用Java和selenium学习解决滑动验证的问题,前
- 1、阿里云DNS的SDK依赖<dependency> <groupId>com.aliyu
- 前言通过adb shell input可以模拟android各种输入事件,比如文字、按键、触摸等等。adb shell inputUsage