您的位置:首页 > 移动开发 > Android开发

Android之单线程下载与多线程下载

2015-09-14 19:34 1046 查看

概述:

单线程下载很简单,就是开启一个线程去下载资源再进行本地保存;

多线程下载是通过RandomAccessFile(随机文件读写操作类)来设置每个线程读取文件的起始点位置,起始点之间的长度即为该线程需要下载的文件大小

下载开始位置:线程id*每条线程下载的数据长度 = ?

下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?

这里用的是URLConnection

单线程下载与多线程下载

public class DownloadActivity extends Activity implements View.OnClickListener {

    private Button mButtonSingle;
    private Button mButtonMuti;

    private SeekBar mSeekBarDownload;
    private int fileLength;
    //handler用于接收多线程下载线程的消息Message,并得到文件下载进度写入进度条SeekBar
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 0x23:
                    mSeekBarDownload.setProgress(msg.arg1*100/fileLength);
                    break;
            }
        }
    };

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

        mSeekBarDownload = (SeekBar) findViewById(R.id.seekBar_download);
        mButtonSingle = (Button) findViewById(R.id.button_download_single);
        mButtonMuti = (Button) findViewById(R.id.button_download_muti);

        mButtonSingle.setOnClickListener(this);
        mButtonMuti.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.button_download_single:
                new SingleDownloadTask().execute();
                break;
            case R.id.button_download_muti:
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        downloadMuti();
                    }
                }).start();
                break;
            default:
                break;
        }
    }

    /**
     * 多线程下载方式
     * 作用是打开网络连接,建立被下载文件存放路径,开启多个下载线程并发送文件下载进度的消息
     */
    private void downloadMuti() {
        try {
            String urlPath = "http://192.168.0.30:8080/MyWebTest/music/aa.mp3";
            URL url = new URL(urlPath);
            //连接下载地址
            URLConnection connection = url.openConnection();
            //得到文件长度
            fileLength = connection.getContentLength();
            //找到或创建下载文件的存放路径
            File file = new File(Environment.getExternalStorageDirectory(),"ee.mp3");
            if(!file.exists()){
                file.createNewFile();
            }
            MutiThread[] threads = new MutiThread[5];
            //进行五次分段下载,因为int型的整除会舍弃余数,最后一个进程下载的长度是从文件长度的4/5到文件总长度
            for(int i=0;i<5;i++){
                MutiThread thread = null;
                if(i==4){
                    thread = new MutiThread(fileLength/5*4,fileLength,urlPath,file.getAbsolutePath());
                }else{
                    thread = new MutiThread(fileLength/5*i,fileLength/5*(i+1)-1,urlPath,file.getAbsolutePath());
                }
                thread.start();
                threads[i] = thread;
            }
            boolean isFinish = true;
            //如果没有下载完全时不断的更新下载进度,数据通过Message传递给handler
            while (isFinish){
                int sum=0;
                for(MutiThread thread:threads){
                    sum+=thread.getSum();
                }
                Message msg = handler.obtainMessage();
                msg.what = 0x23;
                msg.arg1 = sum;
                handler.sendMessage(msg);
                //一般一个被下载的文件可能无法下载完全
                if(sum+10>fileLength){
                    isFinish=false;
                }
                //被隔一秒,更新一次进度
                Thread.sleep(1000);
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //单线程下载,用的是AsyncTask线程
    class SingleDownloadTask extends AsyncTask<String,Integer,String>{
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            mSeekBarDownload.setProgress((int) (values[0]*100.0/values[1]));
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
        }

        @Override
        protected String doInBackground(String... params) {
            try {
                URL url = new URL("http://192.168.0.30:8080/MyWebTest/music/aa.mp3");
                URLConnection connection = url.openConnection();
                int length = connection.getContentLength();
                InputStream is = connection.getInputStream();
                File file = new File(Environment.getExternalStorageDirectory(),"aa.mp3");
                if(!file.exists()){
                    file.createNewFile();
                }
                FileOutputStream fos = new FileOutputStream(file);
                byte[] array = new byte[1024];
                int index = is.read(array);
                int progress = 0;
                while(index!=-1){
                    fos.write(array,0,index);
                    progress+=index;
                    publishProgress(progress,length);
                    index = is.read(array);
                }
                fos.flush();
                fos.close();
                is.close();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
}


多线程的下载线程的写法

public class MutiThread extends Thread {
    private int sum = 0;
    private long start;
    private long end;
    private String urlPath;
    private String filePath;

    public MutiThread(long start, long end, String urlPath, String filePath) {
        this.start = start;
        this.end = end;
        this.urlPath = urlPath;
        this.filePath = filePath;
    }

    public int getSum() {
        return sum;
    }

    @Override
    public void run() {
        try {
            URL url  = new URL(urlPath);
            URLConnection connection = url.openConnection();
            connection.setAllowUserInteraction(true);
            //设置当前线程下载的起点,终点
            connection.setRequestProperty("Range", "bytes=" + start + "-" + end);
            InputStream is = connection.getInputStream();
            byte[] array = new byte[1024];
            File file = new File(filePath);
            //使用java中的RandomAccessFile 对文件进行随机读写操作
            RandomAccessFile randomAccessFile = new RandomAccessFile(file,"rw");
            //设置开始写文件的位置
            randomAccessFile.seek(start);
            int index = is.read(array);
            //开始循环以流的形式读写文件
            while(index!=-1){
                randomAccessFile.write(array,0,index);
                sum += index;
                index = is.read(array);
            }
            randomAccessFile.close();
            is.close();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


结果演示:

单线程下载:



多线程下载:



显然,多线程下载要比单线程下载快得多,但前提是手机是多核的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: