软件编程
位置:首页>> 软件编程>> Android编程>> Android类FileDownloadList分析

Android类FileDownloadList分析

作者:hebedich  发布时间:2022-06-17 02:11:36 

标签:Android,FileDownloadList

先上代码,再来分析


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

分析,待续。

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com