• Android多线程文件下载


    版本信息

    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>

     

  • 相关阅读:
    hdu 1058
    hdu 1003
    hdu 1500
    hdu 1083 最大匹配
    hdu 1370 中国剩余定理
    hdu 1299 数论 分解素因子
    hdu 1299
    poj 1144 求割点
    hdu 1068 最大独立集合
    hdu 1054
  • 原文地址:https://www.cnblogs.com/xidongyu/p/5634235.html
Copyright © 2020-2023  润新知