android多线程下载

实现多线程下载,程序按以下几个步骤来:
1.创建URL对象。
2.获取指定URL对象所指向资源的大小。
3.在本地磁盘上创建一个与网络资源相同大小的空文件。
4.计算每个线程应该下载那个部分。
5.依此创建,启动多条线程来下载网络资源的指定部分。
工具类代码:

public class DownUtil {
//定义下载资源的路径
    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;
        this.targetFile=targetFile;
        threads=new DownThread[threadNum];
    }
    public void download() throws Exception{
        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,"
                +"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");
//      得到文件大小
        fileSize=conn.getContentLength();
        conn.disconnect();
        int currentPartSize=fileSize/threadNum+1;
        RandomAccessFile file=new RandomAccessFile(targetFile, "rw");
//  设置本地文件的大小
        file.setLength(fileSize);
        file.close();
        for (int i = 0; i < threadNum; i++) {
//          计算每条线程的下载的开始位置
            int startPos=i*currentPartSize;
//          每个线程使用一个RandomAccessFile进行下载
            RandomAccessFile currentPart=new RandomAccessFile(targetFile, "rw");
//          定位该线程的下载位置
            currentPart.seek(startPos);
            threads[i]=new DownThread(startPos,currentPartSize,currentPart);
//          启动下载线程
            threads[i].start();
        }
    }
//  获取下载的完成百分比
    public double getCompleteRate(){
//      统计多条线程已经下载的总大小
        int sumSize=0;
        for (int i = 0; i < threadNum; i++) {
            sumSize+=threads[i].length;
        }
        return sumSize*1.0/fileSize;
    }
    public class DownThread extends Thread {
//      当前线程的下载位置
        private int startPos;
//      定义当前线程负责下载的文件大小
        private int currentPartSize;
//      当前线程需要下载的文件块
        private RandomAccessFile currentPart;
//      定义该线程已下载的字节数
        public int length;
        public DownThread(int startPos,int currentPartSize,RandomAccessFile currentPart){
            this.startPos=startPos;
            this.currentPartSize=currentPartSize;
            this.currentPart=currentPart;
        }
        @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,"
                        +"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");
                InputStream inStream=conn.getInputStream();
//              跳过startPos个字节,表明该线程只下载自己负责哪部分文件
                inStream.skip(this.startPos);
                byte[]buffer=new byte[1024];
                int hasRead=0;
                while (length<currentPartSize&&(hasRead=inStream.read(buffer))>0) {
                    currentPart.write(buffer,0,hasRead);
                    length+=hasRead;
                }
                currentPart.close();
                inStream.close();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

上面的工具类包括了一个内部类(线程类),主类可以调用这个工具类进行下载。

主类代码:

public class MultiThreadDown extends Activity {
    EditText url,target;
    Button down;
    ProgressBar bar;
    DownUtil downUtil;
    private int mDownStatus;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_multi_thread_down);
//      获取界面组件
        url=(EditText) findViewById(R.id.url);
        target=(EditText) findViewById(R.id.target);
        down=(Button) findViewById(R.id.down);
        bar=(ProgressBar) findViewById(R.id.bar);
        final Handler handler=new Handler(){
            public void handleMessage(android.os.Message msg) {
                if (msg.what==0x123) {
                    bar.setProgress(mDownStatus);
                }
            };
        };
        down.setOnClickListener(new OnClickListener() {
            public void onClick(View arg0) {
//              初始化DownUtil对象(最后一个参数指定线程数)
                downUtil=new DownUtil(url.getText().toString(), target.getText().toString(), 6);
                new Thread(){
                    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);
//                              发送消息通知界面更新进度条
                                handler.sendEmptyMessage(0x123);
                                if (mDownStatus>=100) {
                                    timer.cancel();
                                }
                            }
                        },0, 100);
                    };
                }.start();
            }
        });
    }
主类不仅使用了工具类来控制程序下载,而且程序还启动了一个定时器,该定时器控制每隔0.1秒查询进度,并且显示进度。
该程序不仅需要访问网络,还需要访问系统SD卡,在SD卡中创建文件,因此必须授予访问网络,访问SD卡文件的权限。
<!-- 在SD卡中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 向SD卡写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 授权访问网络 -->
<uses-permission android:name="android.permission.INTERNET"/>

运行结果如图:
这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值