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>


相关文章
|
17天前
|
数据采集 Java API
Jsoup库能处理多线程下载吗?
Jsoup库能处理多线程下载吗?
|
2月前
|
编解码 数据安全/隐私保护 计算机视觉
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
如何使用OpenCV进行同步和异步操作来打开海康摄像头,并提供了相关的代码示例。
114 1
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
|
24天前
|
供应链 安全 NoSQL
PHP 互斥锁:如何确保代码的线程安全?
在多线程和高并发环境中,确保代码段互斥执行至关重要。本文介绍了 PHP 互斥锁库 `wise-locksmith`,它提供多种锁机制(如文件锁、分布式锁等),有效解决线程安全问题,特别适用于电商平台库存管理等场景。通过 Composer 安装后,开发者可以利用该库确保在高并发下数据的一致性和安全性。
36 6
|
2月前
|
Java 程序员 开发工具
Android|修复阿里云播放器下载不回调的问题
虽然 GC 带来了很多便利,但在实际编码时,我们也需要注意对象的生命周期管理,该存活的存活,该释放的释放,避免因为 GC 导致的问题。
40 2
|
2月前
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
32 1
|
2月前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异:从代码到用户体验
【10月更文挑战第5天】在移动应用开发的广阔天地中,安卓和iOS两大平台各占半壁江山。它们在技术架构、开发环境及用户体验上有着根本的不同。本文通过比较这两种平台的开发过程,揭示背后的设计理念和技术选择如何影响最终产品。我们将深入探讨各自平台的代码示例,理解开发者面临的挑战,以及这些差异如何塑造用户的日常体验。
|
2月前
|
安全 调度 C#
STA模型、同步上下文和多线程、异步调度
【10月更文挑战第19天】本文介绍了 STA 模型、同步上下文和多线程、异步调度的概念及其优缺点。STA 模型适用于单线程环境,确保资源访问的顺序性;同步上下文和多线程提高了程序的并发性和响应性,但增加了复杂性;异步调度提升了程序的响应性和资源利用率,但也带来了编程复杂性和错误处理的挑战。选择合适的模型需根据具体应用场景和需求进行权衡。
|
2月前
|
网络协议 安全 Java
难懂,误点!将多线程技术应用于Python的异步事件循环
难懂,误点!将多线程技术应用于Python的异步事件循环
81 0
|
3月前
|
存储 Java Android开发
🔥Android开发大神揭秘:从菜鸟到高手,你的代码为何总是慢人一步?💻
在Android开发中,每位开发者都渴望应用响应迅速、体验流畅。然而,代码执行缓慢却是常见问题。本文将跟随一位大神的脚步,剖析三大典型案例:主线程阻塞导致卡顿、内存泄漏引发性能下降及不合理布局引起的渲染问题,并提供优化方案。通过学习这些技巧,你将能够显著提升应用性能,从新手蜕变为高手。
35 2