Android类FileDownloadList分析
先上代码,再来分析
publicclassFileDownloadList{
/**上下文*/
privateContextmContext;
/**请求对象*/
privateBaseRequestLimsfileRequest=null;
/**进度条对话框*/
privateAlertDialogprogressDialog=null;
/**进度条控件变量*/
privateProgressBarmProgress;
/**百分比显示控件*/
privateTextViewmProgressPercent;
privateFilelocalFile=null;
/**接收HttpHelper中获取到文件大小后发送的广播,确定文件大小*/
privateDownLoadReceiverreceiver;
/**文件大小*/
privatelongfileLength=-1L;
/**是否已注册广播标志*/
privatebooleancastFlag=false;
/**是否显示进度条标志*/
privatebooleanshowDialog=false;
/**文件下载完的回调接口*/
privateRunnablemCallback=null;
privateHandlermHandler=newHandler(){
@Override
publicvoidhandleMessage(Messagemsg){
super.handleMessage(msg);
inttempSize=(int)localFile.length();
if(tempSize<fileLength){
//文件下载中
if(showDialog){
//显示了进度条的情况下,更新进度条
intprogress=(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(Exceptione){
e.printStackTrace();
}
}
}
}
};
/**
*构造器
*@paramactivity
*/
/**
*构造器
*@paramactivity
*@paramshowDialog显示进度条标志
*/
publicFileDownloadList(Contextcontext,booleanshowDialog){
mContext=context;
this.showDialog=showDialog;
fileRequest=newBaseRequestLims(context,ClientServiceType.FILE_DOWN);
fileRequest.setMethodType(BaseRequestLims.METHOD_TYPE_POST);
fileRequest.setContext(mContext);
}
publicBaseRequestLimsgetFileRequest(){
returnfileRequest;
}
/**
*通过关联类型来下载文件
*@paramfileName文件名称或文件在服务器上的相对路径加名称
*@paramsaveDir保存在本地的文件目录
*@paramsaveName保存在本地的文件名称
*@paramgllx关联类型
*@paramcallback下载后的处理线程
*/
publicvoiddownloadFile(StringfileName,StringsaveDir,StringsaveName,Runnablecallback){
if(callback!=null){
mCallback=callback;
}
FilesaveDirFile=newFile(saveDir);
//judgethesavedirpathexistornot
if(!saveDirFile.exists()){
saveDirFile.mkdirs();
}
localFile=newFile(saveDir,saveName);
if(localFile.isDirectory()){
newAlertDialog.Builder(mContext).setTitle("提示").setMessage("thesavefileisdirectory").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);
}
}
/**
*进入文件下载子线程
*@paramrequest
*/
privatevoidinvokeFile(finalBaseRequestLimsrequest){
try{
if(showDialog){
buildProgressDialog().show();
}
receiver=newDownLoadReceiver();
IntentFilterfilter=newIntentFilter();
filter.addAction("SAVE_DOWNLOAD_FILE");
mContext.registerReceiver(receiver,filter);
castFlag=true;
//下载的子线程
newThread(){
@Override
publicvoidrun(){
super.run();
HttpHelper.invoke(request);
}
}.start();
}catch(Exceptione){
e.printStackTrace();
}
}
/**
*创建进度对话框
*@return
*/
privateAlertDialogbuildProgressDialog(){
AlertDialog.Builderbuilder=newBuilder(mContext);
builder.setTitle("正在下载文件,请稍候...");
RelativeLayoutcontainer=newRelativeLayout(mContext);
mProgress=newProgressBar(mContext);
mProgress.setId("progress".hashCode());
BeanUtils.setFieldValue(mProgress,"mOnlyIndeterminate",Boolean.valueOf(false));
mProgress.setIndeterminate(false);
LayerDrawablelayerDrawable=(LayerDrawable)mContext.getResources().getDrawable(android.R.drawable.progress_horizontal);
ClipDrawableclipDrawable=(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=newTextView(mContext);
mProgressPercent.setId("percent".hashCode());
mProgressPercent.setText("0%");
mProgressPercent.setTextSize(18);
intcontainerPadding=DimensionUtils.dip2Px(mContext,10);
container.setPadding(containerPadding,containerPadding,containerPadding,containerPadding);
LayoutParamsprogressLayoutParams=newLayoutParams(
LayoutParams.MATCH_PARENT,DimensionUtils.dip2Px(mContext,4));
progressLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL);
progressLayoutParams.addRule(RelativeLayout.LEFT_OF,mProgressPercent.getId());
mProgress.setLayoutParams(progressLayoutParams);
LayoutParamspercentLayoutParams=newLayoutParams(
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("取消",newOnClickListener(){
@Override
publicvoidonClick(DialogInterfacedialog,intwhich){
dialog.dismiss();
}
});
progressDialog=builder.create();
returnprogressDialog;
}
classDownLoadReceiverextendsBroadcastReceiver{
@Override
publicvoidonReceive(Contextcontext,Intentintent){
//显示进度条
fileLength=intent.getLongExtra("FILE_LENGTH",-1);
if(showDialog){
mProgress.setMax((int)fileLength);
}
//更新进度条的线程
newThread(){
@Override
publicvoidrun(){
super.run();
while(true){
try{
Thread.sleep(500);
}catch(Exceptione){
e.printStackTrace();
}
mHandler.sendMessage(mHandler.obtainMessage());
//获取下载文件的大小
intloadedSize=(int)localFile.length();
if(loadedSize>=fileLength){
break;
}
}
}
}.start();
}
}
publicDownLoadReceivergetReciver()
{
returnreceiver;
}
}
它的逻辑:
创建一个FileDownloadList对象后,就可以直接使用该下述方法来实现下载功能。
downloadFile(StringfileName,StringsaveDir,StringsaveName,Runnablecallback)
在实现上是这么个意思:
1.在当前上下文,开启下载线程。当获取到要下载的文件的大小时,发送一个广播过来(这部分没有展示在上述代码中)。
2.在当前上下文中,注册一个广播监听器,监听广播标识为SAVE_DOWNLOAD_FILE的广播。首次监听到发出来的广播后,首次发送过来的广播,包含了要下载的文件的大小信息,然后就每隔5毫秒检测本地文件的大小,直到本地文件的大小(loadedSize)大于等于要下载的文件(fileLength)大小时,退出该循环。
在不断检测的过程中,通过mHandler.sendMessage(mHandler.obtainMessage());,让UI线程更新进度条。
下载线程,会不断将服务器返回的数据流,写到本地文件中,所以,本地文件的大小会不断变化,直到,它的大小跟要下载的文件的大小相等时,就退出这个不断检测本地文件大小的线程。
其它没有在上述代码中表现出来的内容(在其它部分的代码中):
1.在invokeFile(finalBaseRequestLimsrequest)方法中,开了一个如下的下载线程.该下载线程,会将服务器返回的文件流,写到本地文件(localFile)中;然后,它还会发送一个标识为SAVE_DOWNLOAD广播,包含的信息有要下载文件的文件大小fileLength。
//下载的子线程
newThread(){
@Override
publicvoidrun(){
super.run();
HttpHelper.invoke(request);
}
}.start();
上述代码存在的问题:
1.上下文,使用的是某个Activity,如果发生系统调用了该Activity的onDestroy()时,下载线程还没有完成,也就意味着,loadedSize的大小还是小于fileLength。从而,那个不断检测本地文件大小的线程就一直在执行着。
即是检测本地文件大小的线程和下载线程还在执行着:
检测本地文件大小的线程:
newThread(){
@Override
publicvoidrun(){
super.run();
while(true){
try{
Thread.sleep(500);
}catch(Exceptione){
e.printStackTrace();
}
mHandler.sendMessage(mHandler.obtainMessage());
//获取下载文件的大小
intloadedSize=(int)localFile.length();
if(loadedSize>=fileLength){
break;
}
}
}
}.start();
下载线程:
newThread(){
@Override
publicvoidrun(){
super.run();
HttpHelper.invoke(request);
}
}.start();
那么,会出现什么问题呢?
1).我可以确定的就是,mContext会出现泄漏。
2).DownLoadReceiver不能正常被取消注册。
分析,待续。