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

一、概述

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

二、服务端准备

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


三、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"?>                                                                                    

四、运行效果



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

更多相关文章

  1. Android(安卓)文件布局一些细节备忘
  2. 让Android中的webview支持页面中的文件上传
  3. zbar android sdk源码编译
  4. Android布局文件的属性值解析
  5. Android(安卓)文件的保存与读取之自带储存空间
  6. Android(安卓)SDK安装教程
  7. 转贴 Android(安卓)开发之旅:又见Hello World!
  8. 分析脚本文件AndroidInitProcess分析心得(1)
  9. Android高手进阶教程(四)之----Android(安卓)中自定义属性(attr.

随机推荐

  1. android VideoView播放工程raw下的视频+
  2. TextView属性android:ellipsize实现跑马
  3. JS获取移动端系统信息(操作系统、操作系
  4. android中Http访问时 connection.getResp
  5. 解决OPPO系统在Android10魔改刘海屏的额
  6. android 获取手机电话号码和短信内容
  7. 第一讲:Android开发环境的搭建
  8. android 纯c/c++开发
  9. android 杀掉进程
  10. listview常用属性记录