转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46883927

一、概述

         说到Android中的文件下载,Android API中明确要求将耗时的操作放到一个子线程中执行,文件的下载无疑是需要耗费时间的,所以要将文件的下载放到子线程中执行。下面,我们一起来实现一个Android中利用多线程下载文件的小例子。

二、服务端准备

        在这个小例子中我以下载有道词典为例,在网上下载有道词典的安装包,在eclipse中新建项目web,将下载的有道词典安装包放置在WebContent目录下,并将项目发布到Tomcat中,具体如下图所示

Android之——多线程下载示例_第1张图片

三、Android实现

 1、布局

        界面上自上而下放置一个TextView,用来提示文本框中输入的信息,一个文本框用来输入网络中下载文件的路径,一个Button按钮,点击下载文件,一个ProgressBar显示下载进度,一个TextView显示下载的百分比。具体布局内容如下:

                

2、自定义ProgressBarListener监听器接口

         新建自定义ProgressBarListener监听器接口,这个接口中定义两个方法,void getMax(int length)用来获取下载文件的长度,void getDownload(int length);用来获取每次下载的长度,这个方法中主要是在多线程中调用,子线程中获取到的数据传递到这两个接口方法中,然后在这两个接口方法中通过Handler将相应的长度信息传递到主线程,更新界面显示信息,具体代码实现如下:

package com.example.inter;/** * 自定义进度条监听器 * @author liuyazhuang * */public interface ProgressBarListener {/** * 获取文件的长度 * @param length */void getMax(int length);/** * 获取每次下载的长度 * @param length */void getDownload(int length);}

3、自定义线程类DownloadThread

          这里通过继承Thread的方式来实现自定义线程操作,在这个类中主要是实现文件的下载操作,在这个类中,定义了一系列与下载有关的实例变量来控制下载的数据,同时通过自定义监听器ProgressBarListener中的void getDownload(int length)方法来跟新界面显示的进度信息。

具体实现如下:

package com.example.download;import java.io.File;import java.io.FileOutputStream;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import com.example.inter.ProgressBarListener;/** * 自定义线程类 * @author liuyazhuang * */public class DownloadThread extends Thread {//下载的线程idprivate int threadId;//下载的文件路径private String path;//保存的文件private File file;//下载的进度条更新的监听器private ProgressBarListener listener;//每条线程下载的数据量private int block;//下载的开始位置private int startPosition;//下载的结束位置private int endPosition;public DownloadThread(int threadId, String path, File file, ProgressBarListener listener, int block) {this.threadId = threadId;this.path = path;this.file = file;this.listener = listener;this.block = block;this.startPosition = threadId * block;this.endPosition = (threadId + 1) * block - 1;}@Overridepublic void run() {super.run();try {//创建RandomAccessFile对象RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");//跳转到开始位置accessFile.seek(startPosition);URL url = new URL(path);//打开http链接HttpURLConnection conn  = (HttpURLConnection) url.openConnection();//设置超时时间conn.setConnectTimeout(5000);//指定请求方式为GET方式conn.setRequestMethod("GET");//指定下载的位置conn.setRequestProperty("Range", "bytes="+startPosition + "-" + endPosition);//不用再去判断状态码是否为200InputStream in = conn.getInputStream();byte[] buffer = new byte[1024];int len = 0;while((len = in.read(buffer)) != -1){accessFile.write(buffer, 0, len);//更新下载进度listener.getDownload(len);}accessFile.close();in.close();} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}}}

4、新建DownloadManager类

         这个类主要是对下载过程的管理,包括下载设置下载后文件要保存的位置,计算多线程中每个线程的数据下载量等等。

具体实现如下:

package com.example.download;import java.io.File;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import android.os.Environment;import com.example.inter.ProgressBarListener;/** * 文件下载管理器 * @author liuyazhuang * */public class DownloadManager {//下载线程的数量private static final int TREAD_SIZE = 3;private File file;/** * 下载文件的方法 * @param path:下载文件的路径 * @param listener:自定义的下载文件监听接口 * @throws Exception */public void download(String path, ProgressBarListener listener) throws Exception{URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5000);conn.setRequestMethod("GET");if(conn.getResponseCode() == 200){int filesize = conn.getContentLength();//设置进度条的最大长度listener.getMax(filesize);//创建一个和服务器大小一样的文件file = new File(Environment.getExternalStorageDirectory(), this.getFileName(path));RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");accessFile.setLength(filesize);//要关闭RandomAccessFile对象accessFile.close();//计算出每条线程下载的数据量int block = filesize % TREAD_SIZE == 0 ? (filesize / TREAD_SIZE) : (filesize / TREAD_SIZE +1 ); //开启线程下载for(int i = 0; i < TREAD_SIZE; i++){new DownloadThread(i, path, file, listener, block).start();}}}/** * 截取路径中的文件名称 * @param path:要截取文件名称的路径 * @return:截取到的文件名称 */private String getFileName(String path){return path.substring(path.lastIndexOf("/") + 1);}}

5、完善MainActivity

      在这个类中首先,找到页面中的各个控件,实现Button按钮的onClick事件,在onClick事件中开启一个线程进行下载操作,同时子线程中获取到的数据,通过handler与Message机制传递到主线程,更新界面显示。

具体实现如下:

package com.example.multi;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.Menu;import android.view.View;import android.widget.EditText;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.Toast;import com.example.download.DownloadManager;import com.example.inter.ProgressBarListener;/** * MainActivity整个应用程序的入口 * @author liuyazhuang * */public class MainActivity extends Activity {protected static final int ERROR_DOWNLOAD = 0;protected static final int SET_PROGRESS_MAX = 1;protected static final int UPDATE_PROGRESS = 2;private EditText ed_path;private ProgressBar pb;private TextView tv_info;private DownloadManager manager;//handler操作private Handler mHandler = new Handler(){public void handleMessage(android.os.Message msg) {switch (msg.what) {case ERROR_DOWNLOAD://提示用户下载失败Toast.makeText(MainActivity.this, "下载失败", Toast.LENGTH_SHORT).show();break;case SET_PROGRESS_MAX://得到最大值int max = (Integer) msg.obj;//设置进度条的最大值pb.setMax(max);break;case UPDATE_PROGRESS://获取当前下载的长度int currentprogress = pb.getProgress();//获取新下载的长度int len = (Integer) msg.obj;//计算当前总下载长度int crrrentTotalProgress = currentprogress + len;pb.setProgress(crrrentTotalProgress);//获取总大小int maxProgress = pb.getMax();//计算百分比float value = (float)currentprogress / (float)maxProgress;int percent = (int) (value * 100);//显示下载的百分比tv_info.setText("下载:"+percent+"%");break;default:break;}};};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);this.ed_path = (EditText) super.findViewById(R.id.ed_path);this.pb = (ProgressBar) super.findViewById(R.id.pb);this.tv_info = (TextView) super.findViewById(R.id.tv_info);this.manager = new DownloadManager();}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}public void download(View v){final String path = ed_path.getText().toString();//下载new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubtry {manager.download(path, new ProgressBarListener() {@Overridepublic void getMax(int length) {// TODO Auto-generated method stubMessage message = new Message();message.what = SET_PROGRESS_MAX;message.obj = length;mHandler.sendMessage(message);}@Overridepublic void getDownload(int length) {// TODO Auto-generated method stubMessage message = new Message();message.what = UPDATE_PROGRESS;message.obj = length;mHandler.sendMessage(message);}});} catch (Exception e) {// TODO: handle exceptione.printStackTrace();Message message = new Message();message.what = ERROR_DOWNLOAD;mHandler.sendMessage(message);}}}).start();}}

6、增加权限

最后,别忘了给应用授权,这里要用到Android联网授权和向SD卡中写入文件的权限。

具体实现如下:

<?xml version="1.0" encoding="utf-8"?>                                                                                    

四、运行效果

Android之——多线程下载示例_第2张图片

Android之——多线程下载示例_第3张图片

Android之——多线程下载示例_第4张图片

Android之——多线程下载示例_第5张图片

Android之——多线程下载示例_第6张图片

提醒:大家可以到http://download.csdn.net/detail/l1028386804/8899957 链接来获取完整的代码示例

更多相关文章

  1. 让Android中的webview支持页面中的文件上传
  2. Android 文件布局一些细节备忘
  3. Android布局文件的属性值解析
  4. Android 文件的保存与读取之自带储存空间
  5. 分析脚本文件AndroidInitProcess分析心得(1)
  6. android读取keystore证书文件
  7. Android NFS文件系统挂载遇到的问题解决方法
  8. Android中关于线程使用的几点注意事项

随机推荐

  1. 浅谈MySQL安装starting the server失败的
  2. MySQL表的碎片整理和空间回收的方法
  3. mysql中锁机制的最全面讲解
  4. Mysql空间清理的几种具体方法
  5. MySQL学习之数据库操作DML详解小白篇
  6. SQL实现时间序列错位还原案列
  7. MySQL学习之数据库表五大约束详解小白篇
  8. Mysql学习之创建和操作数据库及表DDL大全
  9. Mysql学习之数据库检索语句DQL大全小白篇
  10. 关于MySQL分区表的一个性能BUG