首页 > 系统 > Android > 正文

Android类FileDownloadList分析

2020-04-11 11:47:43
字体:
来源:转载
供稿:网友

先上代码,再来分析

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不能正常被取消注册。

分析,待续。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表