Android实例demo18之多线程断点下载

本文详细介绍了断点下载的实现步骤,包括界面设计、HTTP请求、文件大小获取、多线程下载、缓存检查及进度更新。通过XML布局动态添加下载线程,使用RandomAccessFile进行分段下载,并在下载完成后同步删除本地缓存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先补充一个知识点,在第一次创建一个类继承Activity的时候,如果这个类中又定义了接口和内部累(包括匿名内部类)。那么这个时候这个在这里面使用this是当前这个对象的,而不是Activity的。如果想展示界面等必须要使用getapplicationcontext等。但是如果是xml布局文件中添加的Button方法,那么这个在Activity子类中实现的方法,不是一个类,而是一个类中的方法,因此这里面是可以使用this的。

多线程断点下载可以分为以下几个步骤:

(1)xml界面设计

(2)通过http请求获取文件大小,并在本地创建一个同样大小的文件。

(3)创建多线程开始下载

(4)读取缓存,查看是否有断点下载

(5)开始下载更新文件

(6)所有下载全部完成之后删除本地缓存记录

(1)

布局如下,注意下面没有显示出来的是一个线性布局,这里可以动态的添加下载的多线程个数。

mLinearLayout.removeAllViews();

    for (int i = 0; i < 3; i++) {

    ProgressBar mProgressBar = (ProgressBar) View.inflate(this, R.layout.pgb, null);

mLinearLayout.addView(mProgressBar);

mlistbar.add(mProgressBar);

}


(2)在Button的点击响应方法中添加一个子线程

     new Thread(new Runnable() {

@Override

public void run() {

try {

Log.i("2", "2");

URL mUrl = new URL(urlteString);

HttpURLConnection mConnection = (HttpURLConnection) mUrl.openConnection();

mConnection.setRequestMethod("GET");

mConnection.setConnectTimeout(10000);

int statecode = mConnection.getResponseCode();

Log.i("456", "456");

if (statecode == 200) {

long filesize = mConnection.getContentLength();//get file size

File mFile = new File(Environment.getExternalStorageDirectory(), getfilenamefromurl(mUrl));

RandomAccessFile mAccessFile = new RandomAccessFile(mFile, "rw");

mAccessFile.setLength(filesize);

long threadblocksize = filesize/Threadnum;

// 启动下载线程

beginthreaddownload(threadblocksize, Threadnum, filesize, mlistbar,mUrl);

}

mConnection.disconnect();

} catch (Exception e) {

// TODO: handle exception

e.printStackTrace();

}

}

}).start();

这里可以只获取文件的大小:mConnection.getContentLength()

另外创建一个分段下载文件的时候:RandomAccessFile 这个文件类型,可以在任意位置对文件进行读写操作,一般用于文件缓存。

(3)根据分块大小等参数创建子线程开始分段下载

private void beginthreaddownload(long blocksize,int threadnum,long size,List<ProgressBar> mList,URL path){

    for (int i = 0; i < threadnum; i++) {

long blockbeginbyte = i*blocksize;

long blockendbyte = (i+1)*blocksize-1;

if (i == threadnum - 1) {

blockendbyte = size - 1;

}

mList.get(i).setMax((int) (blockendbyte - blockbeginbyte));

new subdownloadthread(i, blockbeginbyte, blockendbyte, path).start();

Log.i("456", "max"+(blockendbyte - blockbeginbyte)+"end");

}

    

    }

同时设置进度条下载进度的最大数值。

(4)检查是否有缓存数据

   private class subdownloadthread extends Thread{

private int threadId;

private long startIndex;

private long endIndex;

private URL path;

    


public subdownloadthread(int threadId, long startIndex, long endIndex,

URL path) {

super();

this.threadId = threadId;

this.startIndex = startIndex;

this.endIndex = endIndex;

this.path = path;

}




@Override

    public void run() {

    // TODO Auto-generated method stub

    //super.run();

    try {

//        检查是否断点下载,更新block的begin end位置

    long currentsize = 0;

        File mposition = new File(Environment.getExternalStorageDirectory(),getfilenamefromurl(path)+threadId + ".txt");

        if (mposition.exists() && mposition.length() > 0) {

    FileInputStream mInputStream = new FileInputStream(mposition);

    BufferedReader mReader = new BufferedReader(new InputStreamReader(mInputStream));

    int blocksizestep = Integer.valueOf(mReader.readLine());

    startIndex += blocksizestep;

    currentsize += blocksizestep;

    mInputStream.close();

    }

注意这里子线程的实现不是通过匿名内部类的方法实现的,而是通过创建一个线程类的子类。注意匿名对象要start。

(5)开始下载并实时保存下载进度以及更新当前下载进度条

//        建立连接

HttpURLConnection mUrlConnection = (HttpURLConnection) path

.openConnection();

mUrlConnection.setRequestMethod("GET");

mUrlConnection.setRequestProperty("Range", "bytes=" + startIndex + "-"+ endIndex);

mUrlConnection.setConnectTimeout(10000);

int code = mUrlConnection.getResponseCode();

Log.i("123", "xxx"+code);

if (code/100 == 2) {

Log.i("123", "123");

InputStream mInputStream = mUrlConnection.getInputStream();

File file = new File(Environment.getExternalStorageDirectory(),getfilenamefromurl(path));

RandomAccessFile finalfile = new RandomAccessFile(file, "rw");

// 指定文件开始写的位置。

finalfile.seek(startIndex);

int len = 0;

byte buffer[] = new byte[40];

while ((len = mInputStream.read(buffer)) != -1) {

RandomAccessFile filepositon = new RandomAccessFile(mposition,"rwd");

finalfile.write(buffer, 0, len);

currentsize += len;

filepositon.write(String.valueOf(currentsize).getBytes());

filepositon.close();

Log.i("ffff", ""+threadId+"curr"+currentsize);

mlistbar.get(threadId).setProgress((int) currentsize);

}

mInputStream.close();

finalfile.close();

}

(6)下载完成 同步删除本地缓存文件,更新handler

synchronized (MainActivity.class) {

threadactiveacount --;

if (threadactiveacount < 1) {

System.out.println("所有的线程都工作完毕了。删除临时记录的文件");

for (int i = 0; i < 3; i++) {

File f = new File(Environment.getExternalStorageDirectory(),getfilenamefromurl(path)+ i + ".txt");

System.out.println(f.delete());

}

Message msg = Message.obtain();

msg.what = DOWNLOAD_OK;

handler.sendMessage(msg);

}

}

因为所有的线程都是在这个MainActivity中实现的,所以所有的同步方法只要设置唯一的MainActivity.class 即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值