简易的多线程下载,并非框架,只是思想而已,好吧思想也算不上

准备工作:
1.需要明白RandomaccessFile类,明白它的构造中有一个输入mode用来决定文件写入的读写方式,比如”rw” 是读写,”rwd” 是为了读取后直接写入目标文件中。
2.简单的线程分块,比如将要下载的文件分为三份,这时候就需要简单的画图分析这里写图片描述


package com.oblivion.loadfile2location;

import android.os.Bundle;
import android.os.Environment;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class MainActivity extends AppCompatActivity {
    private EditText et_path;
    private ProgressBar pb1;
    private ProgressBar pb2;
    private ProgressBar pb3;
    private String path;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_path = (EditText) findViewById(R.id.et_path);
        pb1 = (ProgressBar) findViewById(R.id.pb1_progress);
        pb2 = (ProgressBar) findViewById(R.id.pb2_progress);
        pb3 = (ProgressBar) findViewById(R.id.pb3_progress);
    }

    public void load(View view) {
        path = et_path.getText().toString().trim();
        new Thread() {
            @Override
            public void run() {
                try {
                    //获取URL
                    URL url = new URL(path);
                    //与服务器创建链接
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    //设定返回时长,设定请求方法,以及获取返回的状态码
                    conn.setConnectTimeout(5000);
                    conn.setRequestMethod("GET");
                    int code = conn.getResponseCode();
                    if (code == 200) {
                        //获取要下载的文件的长度
                        int length = conn.getContentLength();
                        //在本地创建随机输入流,为了colon一个有相同长度的文件,此时文件中有长度但是全为空
                        RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory() + "/xxx.apk", "rw");
                        raf.setLength(length);
                        //关闭流,防止OOM异常
                        raf.close();
                        int ThreadNum = 3;
                        //实现多线程下载,需要设定每一个线程要下载的起点与终点
                        int blackSize = (length / ThreadNum);
                        for (int i = 0; i < ThreadNum; i++) {
                            int startThread = i * (blackSize);
                            int endThread = (i + 1) * blackSize - 1;
                            if (i == ThreadNum - 1) {
                                endThread = (int) (length - 1);
                            }
                            //创建线程开始以设定的起点终点
                            new downThread(startThread, endThread, i).start();
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();

                }
            }
        }.start();
    }

    /**
     * 类继承Thread 创建构造函数,创建该线程时传入起点终点以及线程ID
     */
    public class downThread extends Thread {
        private int startThread;
        private int endThread;
        private int ThreadID;

        /**
         * 线程的构造函数
         * @param startThread 开始的位置
         * @param endThread  结束的位置
         * @param i 哪个线程
         */
        public downThread(int startThread, int endThread, int i) {
            this.startThread = startThread;
            this.endThread = endThread;
            this.ThreadID = i;
            System.out.println(startThread + "---" + endThread + "---" + i);
        }

        ;

        @Override
        public void run() {
            try {

                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                //查看文件是否存在
                File oldfile = new File(Environment.getExternalStorageDirectory(), "/" + ThreadID + ".position");
                int currentIndex = 0;
                if (oldfile.exists()) {
                    BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(oldfile)));
                    String Index = br.readLine();
                    br.close();
                    System.out.println(Index);
                    //设定当前进度是读取到的进度
                    currentIndex = Integer.valueOf(Index);
                }
                //告诉服务器 只想下载资源的一部分
                conn.setRequestProperty("Range", "bytes=" + startThread + "-" + endThread);
                InputStream is = conn.getInputStream();
                byte[] buffer = new byte[1024];
                int len = -1;
                RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory() + "/xxx.apk", "rw");
                //设定好流的开始结束位置之后必须设定raf的seek位置
                raf.seek(currentIndex);
                //断点下载的指针位置
                File file = new File(Environment.getExternalStorageDirectory(), "/" + ThreadID + ".position");
                //如果文件不存在就创建新的文件
                if (!file.exists()) {
                    file.createNewFile();
                }
                while ((len = is.read(buffer)) != -1) {
                    //把每个线程下载的数据放在自己的空间里面.
                    raf.write(buffer, 0, len);
                    currentIndex += len;
                    //设定rwd格式是每次写入数据后就能存放到所指定的文件中
                    RandomAccessFile positionraf = new RandomAccessFile(file.getAbsolutePath(), "rwd");
                    //将指针位置存放到文件中,关闭流,防止OOM
                    positionraf.write((startThread + currentIndex - 1 + "").getBytes());
                    // System.out.println(startThread+currentIndex);
                    positionraf.close();
                    SystemClock.sleep(500);
                    //设定进度条
                    switch (ThreadID) {
                        case 0:
                            pb1.setMax(endThread - startThread);
                            pb1.setProgress(currentIndex);
                            break;
                        case 1:
                            pb2.setMax(endThread - startThread);
                            pb2.setProgress(currentIndex);

                            break;
                        case 2:
                            pb3.setMax(endThread - startThread);
                            pb3.setProgress(currentIndex);
                            break;
                    }
                }
                raf.close();
                is.close();
                System.out.println("线程:" + ThreadID + "下载完毕了...");
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }
}

需要添加的权限

 <uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

UI.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.oblivion.loadfile2location.MainActivity">

    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/et_path"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/loadpath" />

        <Button
            android:text="@string/bt_load"
            android:onClick="load"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>


    <ProgressBar
        android:id="@+id/pb1_progress"
        style="?android:progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/ll" />

    <ProgressBar
        android:id="@+id/pb2_progress"
        style="?android:progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/pb1_progress" />

    <ProgressBar
        android:id="@+id/pb3_progress"
        style="?android:progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/pb2_progress" />
</RelativeLayout>

github源码地址

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值