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

Android 单线程下载与多线程下载_第1张图片

一、搭建severlet服务器


上面的图片展示的只是我们在搭建好服务器的情况下,新建一个Serverlet的方式。具体的从头开始搭建Serverlet的方式大家可以查看下面的连接。

Serverlet具体的搭建方法
注:如果之前已经搭建好的服务器,但是现在不能用了,出现404 错误的,可以参考以上代码重新搭建一遍就能用了。

二、单线程下载

  单线程的下载思想就是通过URL来连接Web的下载路径,这样我们一边读入再写出到手机上就可以了。
  由于主线程中不能操作UI界面、不能有耗时操作,这里我们通过之前的异步加载AsyncTask(封装好的Thread)来实现。
注:异步加载AsyncTask中不能使用Toast语句,可以使用Log来代替。

思路

1、新建一个类继承AsyncTask,在它的doInBackground方法中进行URL连接、读入与写出
2、对Button点击事件监听,当有点击时开启该线程即可。

    class SingleDownload extends AsyncTask<String, Integer, String> {
        @Override
        protected String doInBackground(String... params) {
            try {

                              //获得URL路径
                URL url = new URL(
                        "http://192.168.0.35:8080/Myserverlets/music/aa.mp3");
                             //获得URL连接
                URLConnection connection = url.openConnection();
                //获得文件的总长度
                int length = connection.getContentLength();     
                //获得输入流
                InputStream is = connection.getInputStream();   
                //新建要写入的文件  
                File file = new File(Environment.getExternalStorageDirectory(),
                        "bb.mp3");
                if (!file.exists()) {
                    file.createNewFile();
                }
                    //获得输出流
                FileOutputStream os = new FileOutputStream(file);
                //通过字节读取,每次读取1024B
                byte[] array = new byte[1024];
                int sum = 0;
                int index = is.read(array);
                while (index != -1) {
                       //写出array,长度0~index
                    os.write(array, 0, index);
                    sum += index;
                    publishProgress(sum, length);       
                    index = is.read(array);
                }
                os.flush();
                os.close();
                is.close();
            } catch (MalformedURLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {

            super.onProgressUpdate(values);

            Toast.makeText(getApplicationContext(), "执行" + values[0],
                    Toast.LENGTH_SHORT).show();
            progressbar.setProgress((int) (values[0] * 100.0 / values[1]));
            Toast.makeText(getApplicationContext(), "执行" + values[1],
                    Toast.LENGTH_SHORT).show();
        }

        @Override
        protected void onPostExecute(String result) {

            super.onPostExecute(result);

        }

    }
}

Button监听

case R.id.download_single:
            SingleDownload singledownload = new SingleDownload();
            singledownload.execute();

            break;

三、多线程下载

  多线程下载的思想是开启多个线程将一整个文件进行分段现在,下载开始的位置不同,比如我们的一个文件大小为11,假设我们想要开启3个线程,这样我们第一线程的写出位置为0~2,第二个线程的写出位置为3~5,第三个线程的写出位置本来应该是6~8这样我们还剩了一小部分没有写出,因此我们将第三个线程的写出的结束位置修改为10 ,这样就可以全部写出了。
  同样因为网络下载是一种耗时操作,我们需要新启线程,并在线程中新启多个线程同时下载。当按钮点击时调用下面方法。 
步骤:  
1、先写要开启的多个线程
2、再在MainActivity中开启线程来开启多线程(这里我们用了一个Thread数组对多线程进行管理,其实也可以使用线程池来管理Executor来管理) 

代码示例

1、开启的多个线程

public class MultiDownLoad extends Thread {
    private String urlpath;
    private String filepath;
    private long start;
    private long end;
    private long length;
    private long sum=0;
    public MultiDownLoad(String url, String filepath, long start, long end) {
        this.urlpath = url;
        this.filepath = filepath;
        this.start = start;
        this.end = end;
    }

    public long getSum() {
        return sum;
    }


    @Override
    public void run() {
         try {
            URL url=new URL(urlpath);
            URLConnection conn=url.openConnection();    
            conn.setAllowUserInteraction(true);
            conn.setRequestProperty("Range", "bytes="+start+"-"+end);
            InputStream is=conn.getInputStream();

            byte[] array=new byte[1024];
            File file=new File(filepath);
            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();
            }
            if(randomAccessFile!=null){
                randomAccessFile.close();
            }
            if(is!=null){
                is.close();
            }



        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }

}

2、在MainActivity中开启线程来开启多线程,按钮点击时调用该方法。

private void mutidownload() {
        new Thread(){
            @Override
            public void run() {
                 String urlpath="http://192.168.0.35:8080/Myserverlets/music/aa.mp3";
                 try {
                    URL url=new URL(urlpath);
                    URLConnection conn=url.openConnection();
                    length=conn.getContentLength();
                    //
                    String fileName=getFileName(urlpath);   
                    Log.d("文件名",fileName);
                    File file=new File(Environment.getExternalStorageDirectory(),fileName);
                    if(!file.exists()){
                        file.createNewFile();
                    }

                    MultiDownLoad[] multithread=new MultiDownLoad[4];
                    for(int i=0;i<4;i++){
                        MultiDownLoad thread=null;
                        long    start=length/4*i;
                        long    end=length/4*(i+1);
                        if(i==3){
                            end=length;
                        }
                        thread=new MultiDownLoad(urlpath,file.getAbsolutePath(), start, end);                                               
                        thread.start();
                        multithread[i]=thread;

                    }
                    boolean isfinish=true;
                    while(isfinish){                        
                        long sum=0;
                        for(MultiDownLoad thread:multithread){

                             sum+=thread.getSum();
                            }
                        Message msg=handler.obtainMessage();
                            msg.obj=sum;
                            msg.what=0x233;
                            handler.sendMessage(msg);   
                             if(sum+10>=length){
                                 isfinish=false;
                             }
                             Thread.sleep(1000);

                    }                   
                } catch (MalformedURLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }


            }
        }.start();


    }

    //该方法用于获得要保存成的文件名
     private String getFileName(String url){
      return url.substring(url.lastIndexOf("/")+1);
  }

学习注意点:

1、单线程与AsycTask的结合使用
2、多线程的思路(线程中再开多个线程)
3、获得要保存成的文件名的方式
  

你可能感兴趣的:(Android)