服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android类FileDownloadList分析

Android类FileDownloadList分析

2021-03-04 13:18Android开发网 Android

这篇文章主要介绍了Android类FileDownloadList分析,需要的朋友可以参考下

先上代码,再来分析

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
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对象后,就可以直接使用该下述方法来实现下载功能。

?
1
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。

?
1
2
3
4
5
6
7
8
//下载的子线程
   new Thread(){
    @Override
    public void run() {
     super.run();
     HttpHelper.invoke(request);
    }
   }.start();

上述代码存在的问题:

1.上下文,使用的是某个Activity,如果发生系统调用了该Activity的onDestroy()时,下载线程还没有完成,也就意味着,loadedSize的大小还是小于fileLength。从而,那个不断检测本地文件大小的线程就一直在执行着。

即是检测本地文件大小的线程和下载线程还在执行着:

检测本地文件大小的线程:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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();

下载线程:

?
1
2
3
4
5
6
7
new Thread(){
        @Override
        public void run() {
          super.run();
          HttpHelper.invoke(request);
        }
      }.start();

那么,会出现什么问题呢?

1).我可以确定的就是,mContext会出现泄漏。

2). DownLoadReceiver不能正常被取消注册。

分析,待续。

延伸 · 阅读

精彩推荐
  • AndroidAndroid实现固定屏幕显示的方法

    Android实现固定屏幕显示的方法

    这篇文章主要介绍了Android实现固定屏幕显示的方法,实例分析了Android屏幕固定显示所涉及的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    鉴客6182021-03-27
  • AndroidAndroid程序设计之AIDL实例详解

    Android程序设计之AIDL实例详解

    这篇文章主要介绍了Android程序设计的AIDL,以一个完整实例的形式较为详细的讲述了AIDL的原理及实现方法,需要的朋友可以参考下...

    Android开发网4622021-03-09
  • AndroidAndroid CardView+ViewPager实现ViewPager翻页动画的方法

    Android CardView+ViewPager实现ViewPager翻页动画的方法

    本篇文章主要介绍了Android CardView+ViewPager实现ViewPager翻页动画的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    Abby代黎明9592022-03-02
  • AndroidAndroid编程解析XML方法详解(SAX,DOM与PULL)

    Android编程解析XML方法详解(SAX,DOM与PULL)

    这篇文章主要介绍了Android编程解析XML方法,结合实例形式详细分析了Android解析XML文件的常用方法与相关实现技巧,需要的朋友可以参考下...

    liuhe68810042021-05-03
  • AndroidAndroid界面效果UI开发资料汇总(附资料包)

    Android界面效果UI开发资料汇总(附资料包)

    android ui界面设计,友好的界面会提高用户体验度;同时也增强了android ui界面设计的难度,本文提供了一些常用开发资料(有下载哦)感兴趣的朋友可以了解下...

    Android开发网4652021-01-03
  • Android汇总Android视频录制中常见问题

    汇总Android视频录制中常见问题

    这篇文章主要汇总了Android视频录制中常见问题,帮助大家更好地解决Android视频录制中常见的问题,需要的朋友可以参考下...

    yh_thu5192021-04-28
  • AndroidAndroid中AsyncTask详细介绍

    Android中AsyncTask详细介绍

    这篇文章主要介绍了Android中AsyncTask详细介绍,AsyncTask是一个很常用的API,尤其异步处理数据并将数据应用到视图的操作场合,需要的朋友可以参考下...

    Android开发网7432021-03-11
  • AndroidAndroid实现Service获取当前位置(GPS+基站)的方法

    Android实现Service获取当前位置(GPS+基站)的方法

    这篇文章主要介绍了Android实现Service获取当前位置(GPS+基站)的方法,较为详细的分析了Service基于GPS位置的技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    Ruthless8332021-03-31