android多线程下载

来源:互联网 发布:mac 命令行安装wget 编辑:程序博客网 时间:2024/06/18 16:56

实现多线程下载,程序按以下几个步骤来:
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"/>

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

1 0
原创粉丝点击