码迷,mamicode.com
首页 > 移动开发 > 详细

Android多线程文件下载

时间:2016-07-01 21:21:28      阅读:342      评论:0      收藏:0      [点我收藏+]

标签:

版本信息

apply plugin: ‘com.android.application‘

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "xidian.dy.com.chujia"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘
        }
    }
}

dependencies {
    compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
    testCompile ‘junit:junit:4.12‘
    compile ‘com.android.support:appcompat-v7:23.4.0‘
}

亲测可用

布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal" >

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="输入url:" />

                <EditText
                    android:id="@+id/url"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal" >

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="输入保存的文件名:" />

                <EditText
                    android:id="@+id/target"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />
        </LinearLayout>

        <Button
            android:id="@+id/download"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="下载" />

        <ProgressBar
            android:id="@+id/progressBar"
            style="@android:style/Widget.ProgressBar.Horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

</LinearLayout>

下载工具类

package xidian.dy.com.chujia;

/**
 * Created by dy on 2016/6/29.
 */
import android.os.Environment;
import android.os.StrictMode;
import android.util.Log;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Description:
 * 创建ServerSocket监听的主类
 * @author  jph
 * Date:2014.08.27
 */
public class DownUtil
{
    /**下载资源的URL**/
    private String path;
    /**下载的文件的保存位置**/
    private String targetFile;
    /**需要使用多少线程下载资源**/
    private int threadNum;
    /**下载的线程对象**/
    private DownThread[] threads;
    /**下载的文件的总大小**/
    private int fileSize;

    public DownUtil(String path, String targetFile, int threadNum) {
        this.path = path;
        this.threadNum = threadNum;
        // 初始化threads数组
        threads = new DownThread[threadNum];
        this.targetFile = targetFile;
    }

    public void download() throws Exception {
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5 * 1000);
        conn.setReadTimeout(5*1000);
        conn.setRequestMethod("GET");
        conn.setRequestProperty(
                "Accept",
                "image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
                        + "application/x-shockwave-flash, application/xaml+xml, "
                        + "application/vnd.ms-xpsdocument, application/x-ms-xbap, "
                        + "application/x-ms-application, application/vnd.ms-excel, "
                        + "application/vnd.ms-powerpoint, application/msword, */*");
        conn.setRequestProperty("Accept-Language", "zh-CN");
        conn.setRequestProperty("Charset", "UTF-8");
        conn.setRequestProperty("Connection", "Keep-Alive");
        conn.connect();
        if(conn.getResponseCode() == 200){
            // 得到文件大小
            fileSize = conn.getContentLength();
            //关闭连接
            conn.disconnect();
            //计算每个线程下载文件大小
            int currentPartSize = fileSize / threadNum;
            //创建本地文件

            File myfile = new File(Environment.getExternalStorageDirectory(), targetFile);
                if(myfile.exists())
                    myfile.delete();
                else
                    myfile.createNewFile();
                RandomAccessFile file = new RandomAccessFile(myfile, "rwd");
                // 设置本地文件的大小
                file.setLength(fileSize);
                file.close();
                for (int i = 0; i < threadNum; i++) {
                    // //计算线程下载的开始位置和结束位置
                    int startIndex = i * currentPartSize;
                    int endIndex = (i + 1) *currentPartSize - 1;
                    if(i == threadNum - 1){
                        endIndex = fileSize - 1;
                    }
                    // 每个线程使用一个RandomAccessFile进行下载
                    RandomAccessFile currentPart = new RandomAccessFile(myfile, "rwd");
                    threads[i] = new DownThread(currentPart,startIndex, endIndex);
                    threads[i].start();
                }
        }

    }

    // 获取下载的完成百分比
    public double getCompleteRate() {
        // 统计多条线程已经下载的总大小
        int sumSize = 0;
        for (int i = 0; i < threadNum; i++) {
            if(threads[i] == null)
                sumSize += 0;
            else
                sumSize += threads[i].length;
        }
        // 返回已经完成的百分比
        return sumSize * 1.0 / fileSize;
    }

    private class DownThread extends Thread {
        /**当前线程的下载位置**/
        private int startPos;
        /**当前线程下载的结束位置**/
        private int endPos;
        /**当前线程需要下载的文件块**/
        private RandomAccessFile currentPart;
        /**定义该线程已下载的字节数**/
        public int length;

        public DownThread(RandomAccessFile currentPart, int startPos, int endPos) {
            this.startPos = startPos;
            this.currentPart = currentPart;
            this.endPos = endPos;
        }

        @Override
        public void run() {
            try {
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection)url
                        .openConnection();
                conn.setConnectTimeout(5 * 1000);
                conn.setRequestMethod("GET");
                conn.setRequestProperty(
                        "Accept",
                        "image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
                                + "application/x-shockwave-flash, application/xaml+xml, "
                                + "application/vnd.ms-xpsdocument, application/x-ms-xbap, "
                                + "application/x-ms-application, application/vnd.ms-excel, "
                                + "application/vnd.ms-powerpoint, application/msword, */*");
                conn.setRequestProperty("Accept-Language", "zh-CN");
                conn.setRequestProperty("Charset", "UTF-8");
                conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
                conn.connect();
                if(conn.getResponseCode() == 206){
                    InputStream inStream = conn.getInputStream();
                    // 跳过startPos个字节,表明该线程只下载自己负责哪部分文件。
                    byte[] buffer = new byte[4*1024];
                    int hasRead;
                    currentPart.seek(startPos);
                    // 读取网络数据,并写入本地文件
                    while ((hasRead = inStream.read(buffer)) >0 ) {
                        currentPart.write(buffer, 0, hasRead);
                        // 累计该线程下载的总大小
                        length += hasRead;
                    }
                    Log.i(Thread.currentThread().getName(), String.valueOf(length));
                    currentPart.close();
                    inStream.close();
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

主代码

package xidian.dy.com.chujia;

import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {
    EditText url;
    EditText target;
    Button downBn;
    ProgressBar bar;
    DownUtil downUtil;
    private int mDownStatus;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 获取程序界面中的三个界面控件
        url = (EditText) findViewById(R.id.url);
        target = (EditText) findViewById(R.id.target);
        downBn = (Button) findViewById(R.id.download);
        bar = (ProgressBar) findViewById(R.id.progressBar);

        // 创建一个Handler对象
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == 0x123) {
                    bar.setProgress(mDownStatus);
                }
            }
        };

        downBn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
                    return;
                // 初始化DownUtil对象(最后一个参数指定线程数)
                downUtil = new DownUtil(url.getText().toString(),
                        target.getText().toString(), 4);
                new Thread() {
                    @Override
                    public void run(){
                        try {
                            // 开始下载
                            downUtil.download();
                        }
                        catch (Exception e) {
                            e.printStackTrace();
                        }
                        // 定义每秒调度获取一次系统的完成进度
                        final Timer timer = new Timer();
                        timer.schedule(new TimerTask() {
                            @Override
                            public void run() {
                                // 获取下载任务的完成比率
                                double completeRate = downUtil.getCompleteRate();
                                mDownStatus = (int) (completeRate * 100);
                                // 发送消息通知界面更新进度条
                                Log.i(Thread.currentThread().getName(), String.valueOf(mDownStatus));
                                handler.sendEmptyMessage(0x123);
                                // 下载完全后取消任务调度
                                if (mDownStatus >= 100) {
                                    showToastByRunnable(MainActivity.this, "下载完成", 2000);
                                    timer.cancel();
                                }
                            }
                        }, 0, 100);
                    }
                }.start();
            }
        });
    }
    /**
     * 在非UI线程中使用Toast
     * @param context 上下文
     * @param text 用以显示的消息内容
     * @param duration 消息显示的时间
     * */
    private void showToastByRunnable(final Context context, final CharSequence text, final int duration) {
        Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, text, duration).show();
            }
        });
    }
}

权限控制

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="xidian.dy.com.chujia">
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

 

 

Android多线程文件下载

标签:

原文地址:http://www.cnblogs.com/xidongyu/p/5634235.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!