android中级篇之多线程下载
要是先多线程下载,则必须对同一个文件可任意位置的写入 ,java中提供这样一个类可任意写入RandomAccessFile 。通过多线程,可将文件分割成多个子断,每一个线程只需下载一段文件即可。实现效果如图:
下面看代码部分:
1.布局文件 main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="下载路径"
- />
- <EditText
- android:id="@+id/mEditText"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:text="http://android.yesky.com/uploads/attachments/2010-04/27/a5964152.jpg"/>
- <ProgressBar
- android:id="@+id/mBar"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:visibility="invisible"
- style="?android:attr/progressBarStyleHorizontal"/>
- <Button
- android:id="@+id/mButton"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="下载"/>
- </LinearLayout>
2.下载工具类 Download.java
- package com.yin.downloader.utils;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.RandomAccessFile;
- import java.net.HttpURLConnection;
- import java.net.MalformedURLException;
- import java.net.URL;
- import android.content.Context;
- import android.util.Log;
- public class Download {
- private String SDPath = null;
- private static final String TAG = "com.yin.download";
- private RandomAccessFile randomFile = null;
- private URL url;
- private Context context;
- private String urlStr;
- private String fileName;
- private int fileSize;
- private int totalReadSize;
- public Download(String urlStr,String fileName,String SDPath,Context context){
- this.context = context;
- this.fileName = fileName;
- this.urlStr = urlStr;
- this.SDPath = SDPath;
- }
- public void downloadFile(){
- try {
- File file = new File(SDPath+fileName);
- url = new URL(urlStr);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setRequestMethod("GET");
- //获得下载文件的大小
- fileSize = conn.getContentLength();
- //设置线程的大小,考虑手机的性能,并不是越大越好
- int threadSize = 3;
- //每个线程下载文件+的部分大小 +1 避免文件下载不完全
- int block = fileSize / threadSize +1;
- for(int i=0;i<3;i++){
- int startPosition = i * block;
- //创建可任意位置读取的文件
- randomFile = new RandomAccessFile(file, "rw");
- randomFile.seek(startPosition);
- new DownloadThread(i+1, startPosition, block, randomFile).start();
- }
- } catch (MalformedURLException e) {
- Log.e(TAG, "MalformedURLException");
- e.printStackTrace();
- } catch (IOException e) {
- Log.e(TAG, "IOException");
- e.printStackTrace();
- }
- }
- //下载文件的线程
- private class DownloadThread extends Thread{
- private int threadID;
- private int startPosition;
- private int block;
- private RandomAccessFile randomFile;
- public DownloadThread(int threadID, int startPosition, int block,
- RandomAccessFile randomFile) {
- super();
- this.threadID = threadID;
- this.startPosition = startPosition;
- this.block = block;
- this.randomFile = randomFile;
- }
- public void run() {
- try {
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setRequestMethod("GET");
- //文件下载位置 规定的格式 “byte=xxxx-”
- String start = "bytes="+startPosition + "-";
- //设置文件开始的下载位置
- conn.setRequestProperty("Range", start);
- InputStream is = conn.getInputStream();
- byte[] buffer = new byte[4*1024];
- int len = -1;
- int readFileSize = 0;
- while((readFileSize < block) && ((len = is.read(buffer)) != -1)){
- randomFile.write(buffer,0,len);
- readFileSize += len ;
- totalReadSize += readFileSize;
- }
- System.out.println("线程 :"+threadID+" 下载完成");
- is.close();
- randomFile.close();
- conn.disconnect();
- } catch (IOException e) {
- Log.e(TAG+":child", "IOException");
- e.printStackTrace();
- }
- }
- }
- public int getFileSize() {
- return fileSize;
- }
- public void setFileSize(int fileSize) {
- this.fileSize = fileSize;
- }
- public int getTotalReadSize() {
- return totalReadSize;
- }
- public void setTotalReadSize(int totalReadSize) {
- this.totalReadSize = totalReadSize;
- }
- }
3.DownloadActivity.java
- package com.yin.downloader;
- import java.util.Timer;
- import java.util.TimerTask;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.Handler;
- import android.os.Message;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.ProgressBar;
- import android.widget.Toast;
- import com.yin.downloader.utils.Download;
- public class DownloadActivity extends Activity {
- public EditText mEditText;
- public ProgressBar mBar;
- public Button mButton;
- public String urlStr;
- public String fileName;
- public String SDPath = "/sdcard/";
- public int fileSize;
- public int totalReadSize;
- Download download;
- public Handler handler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- mBar.setProgress(download.getTotalReadSize());
- mBar.invalidate();
- }
- };
- public Timer mTimer = new Timer();
- public TimerTask mTask = new TimerTask() {
- @Override
- public void run() {
- Message msg = new Message();
- handler.sendMessage(msg);
- }
- };
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mEditText = (EditText) findViewById(R.id.mEditText);
- mBar = (ProgressBar) findViewById(R.id.mBar);
- mButton = (Button) findViewById(R.id.mButton);
- mButton.setOnClickListener(new ClickEven());
- fileName = "my.jpg";
- //判断SDcard是否存在。
- if(Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED){
- SDPath ="/sdcard/";
- }else{
- Toast.makeText(this, "SDcard不存在", Toast.LENGTH_LONG).show();
- }
- }
- private class ClickEven implements OnClickListener{
- public void onClick(View v) {
- urlStr = mEditText.getText().toString();
- mBar.setVisibility(View.VISIBLE);
- download = new Download(urlStr,fileName,SDPath,DownloadActivity.this);
- download.downloadFile();
- //将progressbar的大小设置为下载文件大小
- mBar.setMax(download.getFileSize());
- //定时刷新
- mTimer.schedule(mTask, 0, 200);
- }
- }
- }
此例实现比较简单,还可以加入断点续传的功能,把程序停止时当前线程现在的位置存入数据库中,再次下载时从数据库中取出即可;