Android实现单线程异步多文件下载的代码

简介:

 现在有一个需求,需要下载的文件有很多个,放在一个开放端口(URL)的目录下,这个目录下的文件会变动,就是文件名不定。现在需要把这个目录下的文件下载到Android设备上。我找了很多资料,发现不能把一个URL目录下的全部文件以文件名的方式列出来(?)。那么,把需要下载的多个文件打包成一个.zip文件放到URL上,下载下来后再通过代码解压,解压时如果有中文名的文件,不能正常解压(这个在另一篇文章中记载)。走另一条道路:需要下载的文件关联到一个点菜系统的菜单的全部图片,文件名就是菜单的图片名。点菜系统的菜单可以从服务器的数据库中查询到。这样就把菜单全部遍历一遍,每个菜单的图片名(如果有的话)和URL目录拼成文件下载路径(经理提出的方法),使用循环遍历下载。

/**
  * 准备下载菜谱图片,检查SDcard是否可用,设置下载更新地址,下载后保存位置信息。
  */
 private void downloadMenuImageCheck() {
  String status = Environment.getExternalStorageState();
  if (!Environment.MEDIA_MOUNTED.equals(status)) {
   ToastUtils.showFailure(getApplicationContext(),
     "SDcard cannot use!");
   return;
  }

  RequestFileInfo requestFileInfo = new RequestFileInfo();
  requestFileInfo.fileParentUrl = "http://192.168.1.103:8181/menupic";
  requestFileInfo.saveFilePath = Environment
    .getExternalStorageDirectory().getAbsolutePath()
    + "/waitab/menupic";

  showDialog(DialogUtil.DIALOG_DOWNLAOD_IMAGE_PROGRESS);   
  new DownlaodUpdateTask().execute(requestFileInfo);
 }

 /**
  * 找出所有菜品数据
  * @return List<menux>
  */
 private List<menux> updateMenux() {
  return mdb.findAll();
 }

 /**
  * 找出所有菜品数据
  * 下载菜品图片类 
  * 遍历菜品数据List,根据每一个菜品图片名字拼出下载路径
  * 多文件循环遍历单线程下载
  * 
  * @author modify by ZX
  * 
  */
 private class DownlaodUpdateTask extends
   AsyncTask<requestfileinfo progressvalue="" basiccallresult=""> {

  @Override
  protected BasicCallResult doInBackground(RequestFileInfo... params) {
   Log.d(TAG, "start doInBackground!"); 
   final RequestFileInfo req = params[0];
   ProgressValue progressValue = new ProgressValue(0, getString(R.string.msg_fetching_menu));
   publishProgress(progressValue);
   
   List<menux> menuxs ;
   menuxs = updateMenux();
   if (menuxs == null) {
    dismissDialog(DialogUtil.DIALOG_DOWNLAOD_IMAGE_PROGRESS); 
    return new BasicCallResult(
      "Can not get menu data! ", false); 
   }
   
   // 根据文件路径创建目录
   File basePath = new File(req.saveFilePath);
   if (!basePath.exists())
    basePath.mkdirs();
  
   int needDownloadImageCount = 0;//记录需要下载的图片数
   int finishDownloadImageCount = 0;//记录完成下载的图片数
   long startTime;
   long endTime;
   int length = 0;
   double totalLength = 0;
   int count = 0;
   
   class ImageInfo{
    public String imageName;
    public String imageMenuTypeGroupx;
    public HttpURLConnection conn;
   }
   List<imageinfo> imageInfos = new ArrayList<imageinfo>();
   
   //遍历菜品,取得需要下载的图片文件的总数量和能连接上的图片文件的总大小和信息
   for (Menux menux : menuxs) {
    try {
     String imageName = menux.getPicname();// 菜品图片名
     if (StringUtils.isNotEmpty(imageName)) {
      needDownloadImageCount += 1;
      URL url = new URL(req.fileParentUrl+ File.separator  
          + java.net.URLEncoder.encode(imageName,
            "UTF-8")); // 如果菜品名是中文,为了解决乱码问题,改变编码方式
      HttpURLConnection conn = (HttpURLConnection) url
        .openConnection();// throws IOException
      Log.i(TAG, "response code:" + conn.getResponseCode());
      if (HttpURLConnection.HTTP_OK == conn.getResponseCode()) {
       length += conn.getContentLength();
       String imageMenuTypeGroupx = menux.getMenutype() + menux.getGroupx();// 菜品分类
       
       ImageInfo imageInfo = new ImageInfo();
       imageInfo.imageName = imageName;
       imageInfo.imageMenuTypeGroupx = imageMenuTypeGroupx;
       imageInfo.conn = conn;
       imageInfos.add(imageInfo);
      }
     }
    }catch(IOException e){
     e.printStackTrace();
    }
   }
   
   if(imageInfos.size() == 0){
    return new BasicCallResult("No image need download! ", false);
   }
   totalLength = StringUtils.bytes2M(length);
   progressValue = new ProgressValue(0, getString(R.string.msg_start_download_menuimage));
   publishProgress(progressValue); 
   
   startTime = System.currentTimeMillis();
   
   // 遍历能够连接上的图片信息下载
   for (ImageInfo imageInfo : imageInfos) {
    try {
     /*
     String imageName = menux.getPicname();// 菜品图片名
     if (StringUtils.isNotEmpty(imageName)) { 
      String imageMenuTypeGroupx = menux.getMenutype()
        + menux.getGroupx();// 菜品分类
      URL url = new URL(req.fileParentUrl+ File.separator  
          + java.net.URLEncoder.encode(imageName,
            "UTF-8")); // 如果菜品名是中文,为了解决乱码问题,改变编码方式
      HttpURLConnection conn = (HttpURLConnection) url
        .openConnection();// throws IOException
      Log.i(TAG, "response code:" + conn.getResponseCode());
      if (HttpURLConnection.HTTP_OK == conn.getResponseCode()) {
      */
     String imageMenuTypeGroupx = imageInfo.imageMenuTypeGroupx;
     String imageName = imageInfo.imageName;
     InputStream is = imageInfo.conn.getInputStream();
       
       /*
        * 用这几种方式打开 is 都可以,用上面一种方式测试是否连接上,若连接上了,再做下载处理
        * 
       InputStream is = conn.getURL().openStream();
       InputStream is = url.openStream();
                            */
       
       // 根据菜品分类创建下一级目录
       File path;
       if (StringUtils.isNotEmpty(imageMenuTypeGroupx)) {
        path = new File(req.saveFilePath
          + File.separator + imageMenuTypeGroupx);
        if (!path.exists())
         path.mkdir();
       } else {
        path = new File(req.saveFilePath);
       }

       File imageFile = new File(path, imageName);
       FileOutputStream fos = new FileOutputStream(
         imageFile);
       //progressValue = new ProgressValue(0, " downloading:");
       byte buffer[] = new byte[1024];
       Log.d(TAG, "preper buffer!");
       finishDownloadImageCount += 1;
       do {
        int numread = is.read(buffer);    
        if (numread <= 0) {
         // publish end
         break;
        }
        count += numread;
        fos.write(buffer, 0, numread);
        Log.d(TAG, "start fos.write!");  
        
        endTime = System.currentTimeMillis();
        double currentLength = StringUtils.bytes2M(count); 
        double kbPerSecond = count * 1f / (endTime - startTime);//即时下载速度因精确到毫秒级的时间,
                                                                      //时间单位太大,会出现 endTime - startTime = 0 的情况,使得
                                                                      // kbPerSecond无限大,改为计算平均下载速度。完整表达式应为
                                                                      //(count / 1000f) / ((endTime - startTime) / 1000f),
                                                                      // b/ms = Kb/S   (b=byte)   
        double downloadTotalTime = (endTime - startTime) / 1000f;
        progressValue.message = String.format(
          "%d/%d\t\t%.2f M/%.2f M\t\t%.2fKb/S\t\t\t%.1f S ", finishDownloadImageCount, needDownloadImageCount,
          currentLength, totalLength, kbPerSecond, downloadTotalTime);
        progressValue.progress = (int) ((((float) count) / length) * DialogUtil.LONG_PROGRESS_MAX);
        publishProgress(progressValue);  

       } while (true);
       fos.flush();
       fos.close();
       is.close();
      //}
     } catch (MalformedURLException e) {
     e.printStackTrace();
     return new BasicCallResult("Wrong url! ", false);
      } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     return new BasicCallResult("Error: "
       + e.getLocalizedMessage(), false);
    }
   }

   BasicCallResult callResult = new BasicCallResult(
     "download finish!", true);
   callResult.data = needDownloadImageCount + "";//int转String
   callResult.data2 = String.valueOf(finishDownloadImageCount);
   return callResult;
  }

  @Override
  protected void onPostExecute(BasicCallResult result) {
   if (result.ok) {
    Log.d(TAG, "download menu image success!"); 
    mProgressDialog.setMessage(getString(R.string.msg_download_image_success));
    //ToastUtils.showSuccess(getApplicationContext(), "congratulation!  download success!");
    if(Integer.parseInt(result.data) > Integer.parseInt(result.data2)){
     ToastUtils.showLong(getApplicationContext(),"needDownload:" + result.data + "   "
       + "finishDownload:" + result.data2 + "   "
       + "you should put all menu images to server");
    } 
   } else {
    Log.d(TAG, "download menu image failed!");
    ToastUtils.showFailure(getApplicationContext(), "5"
      + result.message);
   }
   
   DiSettings.putBoolean(getApplicationContext(),
     DiSettings.KEY_DOWNLOAD_MENU_IMAGE, false);
   
   dismissDialog(DialogUtil.DIALOG_DOWNLAOD_IMAGE_PROGRESS);
  }
  
  @Override
  protected void onProgressUpdate(ProgressValue... values) {   
            Log.d(TAG,values[0].toString());   
            mProgressDialog.setProgress(values[0].progress);   
            mProgressDialog.setMessage(values[0].message);
       }
   
 }
</imageinfo></imageinfo></menux></requestfileinfo></menux></menux>


相关文章
|
10天前
|
Ubuntu 开发工具 Android开发
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
本文介绍了在基于Ubuntu 22.04的环境下配置Python 3.9、安装repo工具、下载和同步AOSP源码包以及处理repo同步错误的详细步骤。
39 0
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
|
15天前
|
数据采集 XML JavaScript
C# 中 ScrapySharp 的多线程下载策略
C# 中 ScrapySharp 的多线程下载策略
|
19天前
|
Java 数据库
异步&线程池 CompletableFuture 异步编排 实战应用 【终结篇】
这篇文章通过一个电商商品详情页的实战案例,展示了如何使用`CompletableFuture`进行异步编排,以解决在不同数据库表中查询商品信息的问题,并提供了详细的代码实现和遇到问题(如图片未显示)的解决方案。
异步&线程池 CompletableFuture 异步编排 实战应用 【终结篇】
|
8天前
|
监控 Java API
Android经典实战之OkDownload:一个经典强大的文件下载开源库,支持断点续传
本文介绍的 OkDownload 是一个专为 Android 设计的开源下载框架,支持多线程下载、断点续传和任务队列管理等功能,具备可靠性、灵活性和高性能特点。它提供了多种配置选项和监听器,便于开发者集成和扩展。尽管已多年未更新,但依然适用于大多数文件下载需求。
50 1
|
10天前
|
JSON JavaScript 前端开发
Android调用Vue中的JavaScript代码
Android调用Vue中的JavaScript代码
12 3
|
10天前
|
开发工具 uml git
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
本文分享了下载AOSP源码的方法,包括如何使用repo工具和处理常见的repo sync错误,以及配置Python环境以确保顺利同步特定版本的AOSP代码。
105 0
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
|
11天前
|
API 开发工具 Android开发
Android源码下载
Android源码下载
75 0
|
14天前
|
Java Windows
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
|
19天前
|
Java
异步&线程池 CompletableFuture 异步编排 【下篇】
这篇文章深入探讨了Java中的`CompletableFuture`类,解释了如何创建异步操作、使用计算完成时的回调方法、异常处理、串行化方法、任务组合以及多任务组合的使用方式,并通过代码示例展示了各种场景下的应用。
异步&线程池 CompletableFuture 异步编排 【下篇】
|
8天前
|
存储 监控 数据库
Android经典实战之OkDownload的文件分段下载及合成原理
本文介绍了 OkDownload,一个高效的 Android 下载引擎,支持多线程下载、断点续传等功能。文章详细描述了文件分段下载及合成原理,包括任务创建、断点续传、并行下载等步骤,并展示了如何通过多种机制保证下载的稳定性和完整性。
16 0