Android0912(Android 網絡URLConnection)(ing多線程下載)

使用URLConnection

URLConnection是一個讀取或寫入的網址的連接,使用URLConnection之前必須連接到遠程資源配置。實例URLConnection是不可重用的:你必須使用一個不同的實例爲每個連接到資源。創建一個URLConnection實例,一般只需要new()出一個URL對象,並傳入目標網址,然後調用一下openConnection()方法即可,如下:

  URL url=new URL("http://www.360.com");
  URLConnection connection=url.openConnection();

之後在調用connection的getInputStream()方法就可以得到服務器返回的輸入流了,(前提是服務器爲運行狀態)接着就對輸入流進行讀取。讀取完成後要記得將輸入流關掉,如下:

InputStream is=connection.getInputStream();
            BufferedReader br=new BufferedReader(new InputStreamReader(is));
            String line=br.readLine();
            StringBuffer buffer=new StringBuffer();
            while(line!=null){
                buffer.append(line);
                line=br.readLine();
            }
            Message msg = handler.obtainMessage();
            msg.what=URL_CONENT;
            msg.obj=buffer.toString().trim();
            handler.sendMessage(msg);
            br.close();
            is.close();

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="網絡連接內容"/>
    <Button
        android:id="@+id/btn_network"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="連接網絡"/>
    <TextView
        android:id="@+id/text_connection"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private Button btn_network;
    private Button btn;
    private TextView textView_connection;
    private static final int URL_CONENT=0x23;
    //在這裏對UI進行更新,將結果顯示到界面上
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case URL_CONENT:
                    String s= (String) msg.obj;
                    textView_connection.setText(s);
                    break;
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_network= (Button) findViewById(R.id.btn_network);
        textView_connection= (TextView) findViewById(R.id.text_connection);
        btn_network.setOnClickListener(this);
        btn= (Button) findViewById(R.id.button);
        btn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_network:
                //開啓線程對UI界面進行更新,將結果顯示到界面上
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                       connectServerlet();
                    }
                }).start();
                break;
            case R.id.button:
                Intent intent=new Intent(MainActivity.this,NetworkActivity.class);
                startActivity(intent);
        }


    }

    private void connectServerlet() {
        try {
            URL url=new URL("http://192.168.0.82:8080/MyServersTest");
//            URL url=new URL("http://www.360.com");
            URLConnection connection=url.openConnection();
            InputStream is=connection.getInputStream();
            //下面對獲取到的輸入流進行讀取
            BufferedReader br=new BufferedReader(new InputStreamReader(is));
            String line=br.readLine();
            StringBuffer buffer=new StringBuffer();
            while(line!=null){
                buffer.append(line);
                line=br.readLine();
            }
            //將讀取到的結果存放到Message中
            Message msg = handler.obtainMessage();
            msg.what=URL_CONENT;
            msg.obj=buffer.toString().trim();
            handler.sendMessage(msg);
            br.close();
            is.close();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

要訪問網絡還要開啓權限,在AndroidManifest.xml中:

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

這裏寫圖片描述

下載

單線程下載

需要利用AsyncTask來執行下載任務,要重寫AsyncTask的四個方法

public class DownloadActivity extends Activity implements View.OnClickListener{
    private Button btn_single_downlaod;
    private Button btn_more_download;
    private ProgressBar mDownloadProgressbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_download);
        mDownloadProgressbar= (ProgressBar) findViewById(R.id.progress_download);
        btn_single_downlaod= (Button) findViewById(R.id.single_download);
        btn_single_downlaod.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
            switch (v.getId()){
                case R.id.single_download:
                    SingleDownloadTask task=new SingleDownloadTask();
                    //調用execute()方法啓用SingleDownloadTask任務
                    task.execute();
                    break;
            }
    }
    class SingleDownloadTask extends AsyncTask<String,Integer ,String>{
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mDownloadProgressbar.setVisibility(View.VISIBLE);
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            //在這裏更新下載速度
            mDownloadProgressbar.setProgress((int) (values[0]*100.0/values[1]));

        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            //在這裏提示下載結果
            btn_single_downlaod.setText("下載完成!");
        }

        @Override
        protected String doInBackground(String... params) {
            //執行具體的下載任務
            try {
//                URL url=new URL("http://192.168.0.30:8080/MyWebTest/music/aa.mp3");
                URL url=new URL("http://192.168.0.82:8080/MyServersTest/Music/rainbow.mp3");
                URLConnection connection=url.openConnection();
                //connection.getContentLength()方法返回響應頭字段指定的字節的內容長度
                int length=connection.getContentLength();
//                publishProgress(length);
                //讀取輸入流的內容
                InputStream is=connection.getInputStream();
                File file=new File (Environment.getExternalStorageDirectory(),"rainbow.mp3");
                if (!file.exists()){
                    file.createNewFile();
                }
                //將讀取的內容寫入文件
                FileOutputStream os=new FileOutputStream(file);
                byte[] array=new byte[1024];
                int sum=0;
                int index=is.read(array);
                while(index!=-1){
                    os.write(array,0,index);
                    sum=+index;
                    //調用publishProgress(Progress...)來更新任務的進度
                    publishProgress(sum,length);
                    index=is.read(array);
                }
                os.flush();
                os.close();
                is.close();


            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return null;
        }
    }
}

服務器端的待下載文件
這裏寫圖片描述
下載過程
這裏寫圖片描述
下載到模擬器裏的文件
這裏寫圖片描述

多線程下載

多線程下載就是將一個文件分爲幾分,交給相應的線程進行處理,由文件長度和分數得到每個線程應該處理的問件長度和開始、結尾處理的部分,最後按照線程的順序將每個線程的文件拼接起來。在最後面的餓結尾處不是都能很好的分配完,所以要特殊處理最後一小段。其他部分基本和單線程一致。這裏的多線程需要一個自定義的線程來處理被分割的各個文件。

activity_download.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ProgressBar
        android:id="@+id/progress_download"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
         style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"/>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <Button
    android:id="@+id/single_download"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="單線程下載"
    />
    <Button
        android:id="@+id/multi_download"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="多線程下載"
        />
</LinearLayout>
</LinearLayout>

MultiThread.java

public class MultiThread extends Thread{
    public MultiThread(long start, long end, String url, String filePath) {
        this.start = start;
        this.end = end;
        this.urlPath = url;
        this.filePath = filePath;
    }
    private int sum=0;
    private long start;
    private long end;
    private String urlPath;
    private String filePath;

    public int getSum() {
        return sum;
    }

    @Override
    public void run() {
        try {
            URL url=new URL(urlPath);
            //URL的openConnection()返回這個網址所指的資源的新連接。
            URLConnection connection=url.openConnection();
            //設置允許用戶交互。
            connection.setAllowUserInteraction(true);
            //設置指定的請求頭字段的值。價值只能被當前的URLConnection實例使用。這種方法只能在建立連接之前調用。
            //第一個參數是設置請求與的頭值 第二個參數指定屬性的新值
            connection.setRequestProperty("Range", "bytes=" + start + "-"
                    + end);
            //讀取輸入流的內容
            InputStream is= connection.getInputStream();
            byte [] array=new byte[1024];
            is.read(array);
            File file=new File(filePath);
            //RandomAccessFile允許在隨機訪問方式中讀取和寫入文件。這是不同於單向順序訪問一個輸入或輸出提供。
            // 如果在讀/寫模式下打開文件,則可使用寫操作。在每次操作之後,可以向前和向後移動讀寫操作的位置。
            //RandomAccessFile(file,"rw")構建了一個基於文件的RandomAccessFile實例,根據模式訪問字符串打開它。
            RandomAccessFile randomAccessFileile=new RandomAccessFile(file,"rw");
            //RandomAccessFile的seek()方法將該文件的文件指針移到一個新的位置,從下面的讀、寫或跳過操作來完成
            randomAccessFileile.seek(start);
            int index=is.read(array);
            while (index!=-1){
                //RandomAccessFile的write()方法寫bytecount字節從字節數組緩衝區這個文件,
                // 當前文件指針開始使用byteoffset作爲第一位在緩衝區獲取字節。
                randomAccessFileile.write(array,0,index);
                sum+=index;
                index=is.read(array);
            }
            randomAccessFileile.close();
            is.close();
            Log.d("此次長度",""+(end-start));
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

DownloadActivity.java

 private void MultiDownloadTask() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String urlPath="http://192.168.0.82:8080/MyServersTest/Picture/imagebac.jpg";
                    URL url=new URL(urlPath);
                    //URL的openConnection()返回這個網址所指的資源的新連接。
                    URLConnection connection=url.openConnection();
                    //connection.getContentLength()方法返回響應頭字段指定的字節的內容長度
                    length = connection.getContentLength();
                    Log.d("下載文件的長度",""+length);
                    //Environment.getExternalStorageDirectory()將文件下載的位置,"image.jpg"下載文件的名字
                    File file=new File(Environment.getExternalStorageDirectory(),"image.jpg");
                    //判斷文件是否存在,不存在,則新建文件
                    if (!file.exists()){
                        file.createNewFile();
                    }
                    //創建線程數組
                    MultiThread[] threads =new MultiThread[5];
                    //給線程數組賦值
                    for (int i=0;i<5;i++){
                        MultiThread thread=null;
                        //將最後一個線程和其他線程區分開來
                        if (i==4){
                            //最後一個線程處理的長度到文件末尾
                            thread=new MultiThread(length / 5*4, length , urlPath, file.getAbsolutePath());
                            Log.d("完成情況","最後看階段段完成"+thread.getSum());
                        }else {
                            //非末尾線程處理的長度爲文件總程度/總線程個數
                            thread=new MultiThread(length / 5 * i, length / 5 * (i + 1)-1, urlPath, file.getAbsolutePath());
                            Log.d("完成情況","第"+i+"段完成"+thread.getSum());
                        }
                        //啓動線程
                        thread.start();
                        //給線程數組賦值
                        threads[i]=thread;
                    }
                    //將各個線程的文件拼接起來
                    boolean isFinish=true;
                    while(isFinish){
                        int sum=0;
                        for (MultiThread thread:threads){
                            sum+= thread.getSum();
                            Log.d("文件長度",""+sum+"本次完成"+thread.getSum());
                        }
                        //將處理文件長度返回給主線程,對UI進行更新
                        Message msg=  handler.obtainMessage();
                        msg.what=0x23;
                        msg.arg1=sum;
                        handler.sendMessage(msg);
                        if(sum+10>= length){
                            isFinish=false;
                        }

                        Thread.sleep(1000);
                    }
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

這裏將多線程下載提成一個方法,最後在多線程下載的按鈕點擊事件裏實現。其結果和單線程一樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章