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>


相关文章
|
19天前
|
编解码 数据安全/隐私保护 计算机视觉
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
如何使用OpenCV进行同步和异步操作来打开海康摄像头,并提供了相关的代码示例。
55 1
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
|
5天前
|
Java 程序员 开发工具
Android|修复阿里云播放器下载不回调的问题
虽然 GC 带来了很多便利,但在实际编码时,我们也需要注意对象的生命周期管理,该存活的存活,该释放的释放,避免因为 GC 导致的问题。
16 2
|
9天前
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
13 1
|
15天前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【10月更文挑战第11天】本文探讨了如何在Kotlin中实现高效的多线程方案,特别是在Android应用开发中。通过介绍Kotlin协程的基础知识、异步数据加载的实际案例,以及合理使用不同调度器的方法,帮助开发者提升应用性能和用户体验。
36 4
|
2月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
96 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
21天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异:从代码到用户体验
【10月更文挑战第5天】在移动应用开发的广阔天地中,安卓和iOS两大平台各占半壁江山。它们在技术架构、开发环境及用户体验上有着根本的不同。本文通过比较这两种平台的开发过程,揭示背后的设计理念和技术选择如何影响最终产品。我们将深入探讨各自平台的代码示例,理解开发者面临的挑战,以及这些差异如何塑造用户的日常体验。
|
15天前
|
安全 调度 C#
STA模型、同步上下文和多线程、异步调度
【10月更文挑战第19天】本文介绍了 STA 模型、同步上下文和多线程、异步调度的概念及其优缺点。STA 模型适用于单线程环境,确保资源访问的顺序性;同步上下文和多线程提高了程序的并发性和响应性,但增加了复杂性;异步调度提升了程序的响应性和资源利用率,但也带来了编程复杂性和错误处理的挑战。选择合适的模型需根据具体应用场景和需求进行权衡。
|
18天前
|
网络协议 安全 Java
难懂,误点!将多线程技术应用于Python的异步事件循环
难懂,误点!将多线程技术应用于Python的异步事件循环
46 0
|
2月前
|
Java Android开发 UED
🧠Android多线程与异步编程实战!告别卡顿,让应用响应如丝般顺滑!🧵
在Android开发中,为应对复杂应用场景和繁重计算任务,多线程与异步编程成为保证UI流畅性的关键。本文将介绍Android中的多线程基础,包括Thread、Handler、Looper、AsyncTask及ExecutorService等,并通过示例代码展示其实用性。AsyncTask适用于简单后台操作,而ExecutorService则能更好地管理复杂并发任务。合理运用这些技术,可显著提升应用性能和用户体验,避免内存泄漏和线程安全问题,确保UI更新顺畅。
76 5