安卓开发-多线程常规实现+xUtils-master开源框架实现 断点下载

《方式一:多线程下载之常规实现》
原理如图:
这里写图片描述
1.创建url

URL url = new URL(getUrl());

//下载来自tomcat下的webapps/ROOT/resource.rar文件,10.0.2.2是安卓映射的服务器的地址,此时不再是localhost或者是本机ip
private String getUrl(){
    return "http://10.0.2.2:8080/resource.rar";
}

2.打开链接

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

3.判断相应码是否为200(没有设置请求头为200)

if(conn.getResponseCode() == 200){

4.得到要下载资源的长度(4.5.6.7在if中)

int contentLength = conn.getContentLength();

5.利用RandomAccessFile在files文件中创建和将要下载文件一样容量的空文件

File file = new File(getFilesDir(), getFileName(getUrl()));
//设置文件权限为可读可写
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.setLength(contentLength);//定义空文件长度

6.计算出每个线程负责下载文件的大小

//MAX_THREAD_NUM为全局变量,设定资源分给几个线程下载
int preThreadLength = contentLength/MAX_THREAD_NUM;

7.对每个线程的任务做迭代下载

for (int i = 0; i < MAX_THREAD_NUM; i++) {
    int startIndex = i * preThreadLength;//线程下载的起始点
    int endIndex = (i + 1) * preThreadLength - 1;//线程下载的结束点
    if(i == MAX_THREAD_NUM - 1){
        endIndex = contentLength - 1;
        }
    //每次从新开启一个新的线程下载,i可用来判断是否下载完毕
    new DownLoadFile(i, startIndex, endIndex).start();
    }

8.创建下载资源线程类:

8.1.创建全局变量:
private int mCurrentThreadNum;//当前线程号(默认从0开始)
private int mStartIndex;//当前线程下载的起始点
private int mEndIndex;//当前线程下载的结束点
private int mLastIndex;//上次下载断点位置
8.2.创建构造器:
public DownLoadFile(int currentThreadNum, int firstIndex, int endIndex){
            mCurrentThreadNum = currentThreadNum;
            mStartIndex = firstIndex;
            mEndIndex = endIndex;
            mLastIndex = firstIndex;
        }
8.3:重写Thread中的run方法:
public void run() {
try {
    //1.创建url
    URL url = new URL(getUrl());
    //2.打开链接
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();

    //3.得到files中的断点文件信息,并将值赋给mLastIndex
    File file = getRecoredFile(mCurrentThreadNum, getFileName(getUrl()));
    if(file.exists()){
        InputStream is = new FileInputStream(file);
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        mLastIndex = Integer.valueOf(reader.readLine());
    }

    //4.设置请求头信息,如果是第一次,就用mStartIndex(下载相关:Range  :  bytes=起始点-结束点)
    conn.setRequestProperty("Range", "bytes=" +( mLastIndex != 0 ? mLastIndex : mStartIndex )+ "-" + mEndIndex);
    //5.判断相应码是否为206,设置下载的请求头后响应码不再是200
    if(conn.getResponseCode() == 206){
        //6.获取输入流
        InputStream is = conn.getInputStream();

        //7.利用RandomAccessFile得到在file下创建好的文件
        File files = new File(getFilesDir(), getFileName(getUrl()));
        RandomAccessFile raf = new RandomAccessFile(files, "rw");
        raf.skipBytes(mLastIndex);//跳过多少个字节

        //8.向文件中写数据
        byte[] buffer = new byte[1024];
        int readCount;
        while((readCount = is.read(buffer)) != -1){
            mLastIndex += readCount;
            raf.write(buffer, 0, readCount);

            //9.根据当前线程数和下载的资源名创建断点位置信息文件,并把数据写入
            File recordFile = getRecoredFile(mCurrentThreadNum, getFileName(getUrl()) );
            RandomAccessFile recordRaf = new RandomAccessFile(recordFile, "rws");
            recordRaf.write((mLastIndex + "").getBytes());

            //10,为进度条设置max和Progress值
            SeekBar sb = (SeekBar) mPbContainerLl.getChildAt(mCurrentThreadNum);
            sb.setMax(mEndIndex - mStartIndex);
            sb.setProgress(mLastIndex);
        }
        //11.下载完成后将断点位置文件删除
        for (int i = 0; i < MAX_THREAD_NUM; i++) {
            getRecoredFile(mCurrentThreadNum, getFileName(getUrl())).delete();
        }


//12.下载完成的提示
if(mCurrentThreadNum == MAX_THREAD_NUM - 1){
    Log.v("520it", "下載完成");
    runOnUiThread(new Runnable() {
    @Override
    public void run() {
    Toast.makeText(MainActivity.this, "下載完成!", Toast.LENGTH_SHORT).show();
    }
});

    }
  }
} catch (Exception e) {
    e.printStackTrace();
  }
}


//根据当前线程数和下载的资源名创建断点位置信息文件
private File getRecoredFile(int currentThreadNum,
        String fileName) {
    String recordFileName = fileName.substring(0, fileName.lastIndexOf(".")) + "#" + currentThreadNum + ".txt";
    return new File(getFilesDir(),recordFileName);
}

9.完整代码:

package com.m520it.downloadofmultithreadpoint;

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

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.Toast;

public class MainActivity extends Activity {
    private int MAX_THREAD_NUM = 3;
    private LinearLayout mPbContainerLl;



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

        mPbContainerLl = (LinearLayout) findViewById(R.id.pbContainer_ll);

    }

    public void downLoadOnClick(View v){
        for (int i = 0; i < MAX_THREAD_NUM; i++) {
            LayoutInflater inflater = LayoutInflater.from(this);
            View view = inflater.inflate(R.layout.pbcontainer_layout, null);
            mPbContainerLl.addView(view.findViewById(R.id.pb));
        }

        new Thread(){
            public void run() {
                try {
                    //1.创建url
                    URL url = new URL(getUrl());
                    //2.打开链接
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    //3.判断相应码是否为200(没有设置请求头为200)
                    if(conn.getResponseCode() == 200){
                        //4.得到文件的长度
                        int contentLength = conn.getContentLength();
                        //5.利用RandomAccessFile在files文件中创建和将要下载文件一样容量的空文件
                        File file = new File(getFilesDir(), getFileName(getUrl()));
                        RandomAccessFile raf = new RandomAccessFile(file, "rw");//设置文件权限为可读可写
                        raf.setLength(contentLength);//定义空文件长度
                        //6.计算出每个线程负责下载文件的大小
                        int preThreadLength = contentLength/MAX_THREAD_NUM;
                        //7.对每个线程的任务做迭代下载
                        for (int i = 0; i < MAX_THREAD_NUM; i++) {
                            int startIndex = i * preThreadLength;//线程下载的起始点
                            int endIndex = (i + 1) * preThreadLength - 1;//线程下载的结束点,最后一个线程负责下载其他线程剩下的所有任务
                            if(i == MAX_THREAD_NUM - 1){
                                endIndex = contentLength - 1;
                            }
                            Log.v("520it", "startup=" + startIndex + " endIndex=" + endIndex);
                            new DownLoadFile(i, startIndex, endIndex).start();//每次从新开启一个新的线程下载,i可用来判断是否下载完毕
                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
        }.start();
    }


    class DownLoadFile extends Thread{
        private int mCurrentThreadNum;//当前线程号(默认从0开始)
        private int mStartIndex;//当前线程下载的起始点
        private int mEndIndex;//当前线程下载的结束点
        private int mLastIndex;//上次下载断点位置

        public DownLoadFile(int currentThreadNum, int firstIndex, int endIndex){
            mCurrentThreadNum = currentThreadNum;
            mStartIndex = firstIndex;
            mEndIndex = endIndex;
            mLastIndex = firstIndex;
        }

        public void run() {
            try {
                //1.创建url
                URL url = new URL(getUrl());
                //2.打开链接
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();

                //3.得到files中的断点文件信息,并将值赋给mLastIndex
                File file = getRecoredFile(mCurrentThreadNum, getFileName(getUrl()));
                if(file.exists()){
                    InputStream is = new FileInputStream(file);
                    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                    mLastIndex = Integer.valueOf(reader.readLine());
                }

                //4.设置请求头信息,如果是第一次,就用mStartIndex(下载相关:Range  :  bytes=起始点-结束点)
                conn.setRequestProperty("Range", "bytes=" +( mLastIndex != 0 ? mLastIndex : mStartIndex )+ "-" + mEndIndex);
                //5.判断相应码是否为206,设置下载的请求头后响应码不再是200
                if(conn.getResponseCode() == 206){
                    //6.获取输入流
                    InputStream is = conn.getInputStream();

                    //7.利用RandomAccessFile得到在file下创建好的文件
                    File files = new File(getFilesDir(), getFileName(getUrl()));
                    RandomAccessFile raf = new RandomAccessFile(files, "rw");
                    raf.skipBytes(mLastIndex);//跳过多少个字节

                    //8.向文件中写数据
                    byte[] buffer = new byte[1024];
                    int readCount;
                    while((readCount = is.read(buffer)) != -1){
                        mLastIndex += readCount;
                        raf.write(buffer, 0, readCount);

                        //9.根据当前线程数和下载的资源名创建断点位置信息文件,并把 
                        File recordFile = getRecoredFile(mCurrentThreadNum, getFileName(getUrl()) );
                        RandomAccessFile recordRaf = new RandomAccessFile(recordFile, "rws");
                        recordRaf.write((mLastIndex + "").getBytes());

                        //为进度条设置max和Progress值
                        SeekBar sb = (SeekBar) mPbContainerLl.getChildAt(mCurrentThreadNum);
                        sb.setMax(mEndIndex - mStartIndex);
                        sb.setProgress(mLastIndex);
                    }
                    //下载完成后将断点位置文件删除
                    for (int i = 0; i < MAX_THREAD_NUM; i++) {
                        getRecoredFile(mCurrentThreadNum, getFileName(getUrl())).delete();
                    }


                    //下载完成的提示
                    if(mCurrentThreadNum == MAX_THREAD_NUM - 1){
                        Log.v("520it", "下載完成");
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(MainActivity.this, "下載完成!", Toast.LENGTH_SHORT).show();
                            }
                        });

                    }

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private File getRecoredFile(int currentThreadNum,
                String fileName) {
            String recordFileName = fileName.substring(0, fileName.lastIndexOf(".")) + "#" + currentThreadNum + ".txt";
            return new File(getFilesDir(),recordFileName);
        }

    }


    private String getFileName(String url){
        return url.substring(url.lastIndexOf("/") + 1);
    }

    private String getUrl(){
        return "http://10.0.2.2:8080/resource.rar";
    }



}

10.RandomAccessFile的功能总结:

10.1:在指定位置创建一个指定大小的空文件:
File file = new File(getFilesDir(), getFileName(getUrl()));
//设置文件权限为可读可写
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.setLength(contentLength);//定义空文件长度
10.2:可在指定文件内跳过指定个数的字节进行写入数据
File files = new File(getFilesDir(), getFileName(getUrl()));
RandomAccessFile raf = new RandomAccessFile(files, "rw");
raf.skipBytes(mLastIndex);//跳过多少个字节

raf.write(buffer, 0, readCount);

《方式二:xUtils-master开源框架实现断点下载》
1.引入框架,如图:
这里写图片描述
2.创建一个下载按钮,为其设置下载点击事件:

public void downLoadClick(View v){
    //1.创建httpUtils对象
    HttpUtils httpUtils = new HttpUtils();

    //创建资源文件保存位置文件
    File file = new File(getFilesDir(), getFileName(getUrl()));
    //2.调用下载函数(资源路径,保存资源位置的绝对路径,是否支持断点下载,请求回调函数重写)
    httpUtils.download(getUrl(), file.getAbsolutePath(), true, new RequestCallBack<File>()
     {
        @Override
        public void onSuccess(ResponseInfo<File> responseInfo) {
            Toast.makeText(MainActivity.this, "下載完成", Toast.LENGTH_SHORT).show();
            Log.v("520it", "下載完成");
        }
        @Override
        public void onFailure(HttpException error, String msg) {
            // TODO Auto-generated method stub
        }

    });
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据网上寻找的资料,加上自己的整合,打包的一个Android多线下载。可以实现断点下载,暂停继续取消下载,能够显示现在已完成大小,文件大小,完成度,下载速度等。使用方法如下: public class MainActivity extends Activity implements OnClickListener,DownloadListener{ private static final String TAG = "MainActivity"; private static final String SD_PATH = Environment.getExternalStorageDirectory().getPath(); private boolean isPause = false; private MultiThreadDownload multiThreadDownload ; private Button buttonDownload; private Button buttonCancel; private TextProgressBar progressBarTest;//可以使用普通的进度,该进度条是可以显示现在完成度 private TextView textInfo; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);//布局文件就是两个简单的按钮一个用于暂停继续下载,一个用于取消任务,还有一个文本用于显示已完成,文件大小,下载完成度,下载速度等信息以及一个进度条。 //http://d1.apk8.com:8020/game/plantsvszombies2.apk buttonDownload = (Button)findViewById(R.id.buttonDownload); buttonDownload.setText("单击下载"); buttonDownload.setOnClickListener(this); progressBarTest = (TextProgressBar) findViewById(R.id.progressBarTest); textInfo = (TextView) findViewById(R.id.textInfo); buttonCancel = (Button) findViewById(R.id.buttonCancel); buttonCancel.setOnClickListener(this); } @Override public void onClick(View v) { String downloadUrl = "http://dldir1.qq.com/invc/qqpinyin/QQInput4.1_1133(1001).apk"; String savePath = SD_PATH+File.separator+"downloadHelper"+File.separator; String fileName = "QQInput.apk"; switch(v.getId()){ case R.id.buttonDownload: if(!isPause){ multiThreadDownload = new MultiThreadDownload(MainActivity.this,downloadUrl, savePath, fileName, this); multiThreadDownload.start(); buttonDownload.setText("下载..."); isPause = true; }else{ buttonDownload.setText("暂停..."); isPause = false; multiThreadDownload.onPause(); multiThreadDownload = null; } break; case R.id.buttonCancel: if(multiThreadDownload==null){ multiThreadDownload = new MultiThreadDownload(MainActivity.this,downloadUrl, savePath, fileName, this); } Log.d(TAG, ""+multiThreadDownload.isDownload()); if(multiThreadDownload.isDownload()){ multiThreadDownload.onCancel(); isPause = false; } multiThreadDownload = null; break; } } private Handler multiHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); if(msg.what==1){ Bundle data = msg.getData(); float downloadSpeed = data.getFloat("downloadSpeed"); boolean speedHigh = false; if(downloadSpeed>500){ speedHigh = true; downloadSpeed/=1024; } progressBarTest.setProgress(data.getInt("completedSize")); textInfo.setText(String.format("已完成:%.2fMB", data.getInt("completedSize")/1024f/1024)+"/"+ String.format("总大小:%.2fMB", data.getInt("fileSize")/1024f/1024)+"\n"+ String.format("进度:%.2f%%", data.getBoolean("isCompleted")?100.00:data.getFloat("downloadPercent"))+"/"+ String.format(speedHigh?"速度:%.2fM/S":"速度:%.2fKB/S", downloadSpeed)); if(data.getBoolean("isCompleted")){ buttonDownload.setText("下载完成"); textInfo.setText("下载完成"); } } } }; @Override public void onDownloading(boolean isCompleted,boolean isPause,boolean isCancel,int fileSize,int completedSize,int downloadedSize,float downloadPercent, float downloadSpeed) { Log.d("MainActivity", isCompleted+"||"+isPause+"||"+completedSize+"||"+downloadedSize+"||"+downloadPercent+"||"+downloadSpeed); Message message = Message.obtain(); message.what = 1; Bundle data = new Bundle(); data.putBoolean("isCancel", isCancel); data.putBoolean("isCompleted", isCompleted); data.putInt("fileSize", fileSize); data.putInt("completedSize", completedSize); data.putInt("downloadedSize", downloadedSize); data.putFloat("downloadPercent", downloadPercent); data.putFloat("downloadSpeed", downloadSpeed); message.setData(data); multiHandler.sendMessage(message); } @Override public void onBeforeDownload(boolean isCompleted,boolean isPause,boolean isCancel,int fileSize){ progressBarTest.setMax(fileSize); } @Override public void onAfterDownload(boolean isCompleted,boolean isPause,boolean isCancel,int fileSize){ } @Override public void onPause(boolean isCompelted,boolean isPause,boolean isCancel,int fileSize,int completedSize,int downloadedSize,float downloadPercent,float downloadSpeed){ textInfo.setText("暂停..."); Log.d(TAG, "暂停..."); } @Override public void onCancelDownload(){ progressBarTest.setProgress(0); textInfo.setText("下载取消"); buttonDownload.setText("重新下载"); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值