Android进阶:实现多线程下载文件

本文介绍了一种基于多线程技术实现文件下载的方法。通过将文件分割成多个部分,并利用RandomAccessFile进行读写操作,进而实现并发下载。文章详细展示了如何在Android环境中创建多线程下载应用。

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

多线程下载大概思路就是通过Range 属性实现文件分段,然后用RandomAccessFile 来读写文件,最终合并为一个文件

 

首先看下效果图

 

 

创建工程 ThreadDemo
首先布局文件 threaddemo.xml

 

<?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:orientation="vertical" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
        > 
    <TextView    
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content"   
        android:text="下载地址" 
        /> 
    <TextView 
        android:id="@+id/downloadurl" 
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content"   
        android:lines="5" 
        /> 
    <TextView    
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content"   
        android:text="线程数" 
        /> 
    <EditText 
        android:id="@+id/downloadnum" 
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content"   
        /> 
    <ProgressBar 
        android:id="@+id/downloadProgressBar" 
        android:layout_width="fill_parent"   
        style="?android:attr/progressBarStyleHorizontal" 
        android:layout_height="wrap_content"   
        /> 
    <TextView 
        android:id="@+id/downloadinfo" 
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content"   
        android:text="下载进度 0" 
        /> 
    <Button 
        android:id="@+id/downloadbutton" 
        android:layout_width="wrap_content"   
        android:layout_height="wrap_content"   
        android:text="开始下载" 
        /> 
    </LinearLayout> 

主界面 Acitivity

 

    public class ThreadDownloadDemo extends Activity {  
       
        private TextView downloadurl;  
        private EditText downloadnum;  
        private Button downloadbutton;  
        private ProgressBar downloadProgressBar;  
        private TextView downloadinfo;  
        private int downloadedSize = 0;  
        private int fileSize = 0;  
          
        private long downloadtime;  
       
        @Override 
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.threaddemo);  
       
            downloadurl = (TextView) findViewById(R.id.downloadurl);  
            downloadurl.setText("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3");  
            downloadnum = (EditText) findViewById(R.id.downloadnum);  
            downloadinfo = (TextView) findViewById(R.id.downloadinfo);  
            downloadbutton = (Button) findViewById(R.id.downloadbutton);  
            downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);  
            downloadProgressBar.setVisibility(View.VISIBLE);  
            downloadProgressBar.setMax(100);  
            downloadProgressBar.setProgress(0);  
            downloadbutton.setOnClickListener(new OnClickListener() {  
                public void onClick(View v) {  
                    download();  
                    downloadtime = SystemClock.currentThreadTimeMillis();  
                }  
            });  
        }  
       
        private void download() {  
            // 获取SD卡目录  
            String dowloadDir = Environment.getExternalStorageDirectory()  
                    + "/threaddemodownload/";  
            File file = new File(dowloadDir);  
            //创建下载目录  
            if (!file.exists()) {  
                file.mkdirs();  
            }  
              
            //读取下载线程数,如果为空,则单线程下载  
            int downloadTN = Integer.valueOf("".equals(downloadnum.getText()  
                    .toString()) ? "1" : downloadnum.getText().toString());  
            String fileName = "hetang.mp3";  
            //开始下载前把下载按钮设置为不可用  
            downloadbutton.setClickable(false);  
            //进度条设为0  
            downloadProgressBar.setProgress(0);  
            //启动文件下载线程  
            new downloadTask("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3", Integer  
                    .valueOf(downloadTN), dowloadDir + fileName).start();  
        }  
       
        Handler handler = new Handler() {  
            @Override 
            public void handleMessage(Message msg) {  
                //当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息  
                int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();  
                if (progress == 100) {  
                    downloadbutton.setClickable(true);  
                    downloadinfo.setText("下载完成!");  
                    Dialog mdialog = new AlertDialog.Builder(ThreadDownloadDemo.this)  
                        .setTitle("提示信息")  
                        .setMessage("下载完成,总用时为:"+(SystemClock.currentThreadTimeMillis()-downloadtime)+"毫秒")  
                        .setNegativeButton("确定", new DialogInterface.OnClickListener(){  
                            @Override 
                            public void onClick(DialogInterface dialog, int which) {  
                                dialog.dismiss();  
                            }  
                        })  
                        .create();  
                    mdialog.show();  
                } else {  
                    downloadinfo.setText("当前进度:" + progress + "%");  
                }  
                downloadProgressBar.setProgress(progress);  
            }  
       
        };  
       
          
        public class downloadTask extends Thread {  
            private int blockSize, downloadSizeMore;  
            private int threadNum = 5;  
            String urlStr, threadNo, fileName;  
       
            public downloadTask(String urlStr, int threadNum, String fileName) {  
                this.urlStr = urlStr;  
                this.threadNum = threadNum;  
                this.fileName = fileName;  
            }  
       
            @Override 
            public void run() {  
                FileDownloadThread[] fds = new FileDownloadThread[threadNum];  
                try {  
                    URL url = new URL(urlStr);  
                    URLConnection conn = url.openConnection();  
                    //防止返回-1  
                    InputStream in = conn.getInputStream();  
                    //获取下载文件的总大小  
                    fileSize = conn.getContentLength();  
                    Log.i("bb", "======================fileSize:"+fileSize);  
                    //计算每个线程要下载的数据量  
                    blockSize = fileSize / threadNum;  
                    // 解决整除后百分比计算误差  
                    downloadSizeMore = (fileSize % threadNum);  
                    File file = new File(fileName);  
                    for (int i = 0; i < threadNum; i++) {  
                        Log.i("bb", "======================i:"+i);  
                        //启动线程,分别下载自己需要下载的部分  
                        FileDownloadThread fdt = new FileDownloadThread(url, file, i * blockSize, (i + 1) * blockSize - 1);  
                        fdt.setName("Thread" + i);  
                        fdt.start();  
                        fds[i] = fdt;  
                    }  
                    boolean finished = false;  
                    while (!finished) {  
                        // 先把整除的余数搞定  
                        downloadedSize = downloadSizeMore;  
                        finished = true;  
                        for (int i = 0; i < fds.length; i++) {  
                            downloadedSize += fds[i].getDownloadSize();  
                            if (!fds[i].isFinished()) {  
                                finished = false;  
                            }  
                        }  
                        handler.sendEmptyMessage(0);  
                        //线程暂停一秒  
                        sleep(1000);  
                    }  
                } catch (Exception e) {  
                    e.printStackTrace();  
                }  
       
            }  
        }  
    } 

这里启动线程将文件分割为几个部分,每一个部分再启动一个线程去下载数据

 

下载文件的线程

 

    public class FileDownloadThread extends Thread{  
        private static final int BUFFER_SIZE=1024;  
        private URL url;  
        private File file;  
        private int startPosition;  
        private int endPosition;  
        private int curPosition;  
        //标识当前线程是否下载完成  
        private boolean finished=false;  
        private int downloadSize=0;  
        public FileDownloadThread(URL url,File file,int startPosition,int endPosition){  
            this.url=url;  
            this.file=file;  
            this.startPosition=startPosition;  
            this.curPosition=startPosition;  
            this.endPosition=endPosition;  
        }  
        @Override 
        public void run() {  
            BufferedInputStream bis = null;  
            RandomAccessFile fos = null;                                                 
            byte[] buf = new byte[BUFFER_SIZE];  
            URLConnection con = null;  
            try {  
                con = url.openConnection();  
                con.setAllowUserInteraction(true);  
                //设置当前线程下载的起止点  
                con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);  
                Log.i("bb", Thread.currentThread().getName()+"  bytes=" + startPosition + "-" + endPosition);  
                //使用java中的RandomAccessFile 对文件进行随机读写操作  
                fos = new RandomAccessFile(file, "rw");  
                //设置写文件的起始位置  
                fos.seek(startPosition);  
                bis = new BufferedInputStream(con.getInputStream());    
                //开始循环以流的形式读写文件  
                while (curPosition < endPosition) {  
                    int len = bis.read(buf, 0, BUFFER_SIZE);                  
                    if (len == -1) {  
                        break;  
                    }  
                    fos.write(buf, 0, len);  
                    curPosition = curPosition + len;  
                    if (curPosition > endPosition) {  
                        downloadSize+=len - (curPosition - endPosition) + 1;  
                    } else {  
                        downloadSize+=len;  
                    }  
                }  
                //下载完成设为true  
                this.finished = true;  
                bis.close();  
                fos.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
       
        public boolean isFinished(){  
            return finished;  
        }  
       
        public int getDownloadSize() {  
            return downloadSize;  
        }  
    } 

 

这里通过RandomAccessFile 的seek方法定位到相应的位置 并实时记录下载量

 

当然这里需要联网和访问SD卡 所以要加上相应的权限

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


本文地址 : http://www.fengfly.com/plus/view-203373-1.html   挑错   推荐
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值