Android應用開發(fā):網(wǎng)絡編程2

網(wǎng)絡編程

1. 使用HttpClient發(fā)送get請求

HttpClient是Apache開發(fā)的第三方框架,Google把它封裝到了Android API中赐劣,用于發(fā)送HTTP請求嫉拐。

在Android.jar包中,可以看到有很多java的API魁兼,這些都是被Android改寫的API婉徘,也可以看到Android封裝了大量的Apache API。

img
img
img

示例:res\layout\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"
    tools:context=".MainActivity" 
    android:orientation="vertical">

    <EditText
        android:id="@+id/et_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <EditText
        android:id="@+id/et_pass"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    
    <Button 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="get登陸"
        android:onClick="click1"
        />
    
    <Button 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="post登陸"
        android:onClick="click2"
        />
</LinearLayout>

src/cn.itcast.getmethod/MainActivity.java

package cn.itcast.getmethod;

import java.io.InputStream;
import java.net.URLEncoder;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import cn.itcast.getmethod.tool.Tools;

public class MainActivity extends Activity {

        Handler handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                        Toast.makeText(MainActivity.this, (String)msg.obj, 0).show();
                }
        };
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        }
        
        public void click1(View v){
                
                EditText et_name = (EditText)findViewById(R.id.et_name);
                EditText et_pass = (EditText)findViewById(R.id.et_pass);
                
                String name = et_name.getText().toString();
                String pass = et_pass.getText().toString();
                
                final String path = "http://192.168.1.100:8080/Web/servlet/Login?name=" + URLEncoder.encode(name) + "&pass=" + pass;
                
                Thread t = new Thread(){
                        @Override
                        public void run() {
                                //1. 創(chuàng)建客戶端對象
                                //HttpClient是一個接口咐汞,不要new一個HttpClient對象盖呼,否則要實現(xiàn)很多的方法
                                HttpClient client = new DefaultHttpClient();
                                
                                //2. 創(chuàng)建Http GET請求對象
                                HttpGet get = new HttpGet(path);
                                
                                try {
                                        //3. 使用客戶端發(fā)送get請求
                                        HttpResponse response = client.execute(get);
                                        //獲取狀態(tài)行
                                        StatusLine line = response.getStatusLine();
                                        //從狀態(tài)行中拿到狀態(tài)碼
                                        if(line.getStatusCode() == 200){
                                                //獲取實體,實體里存放的是服務器返回的數(shù)據(jù)的相關信息
                                                HttpEntity entity = response.getEntity();
                                                //獲取服務器返回的輸入流
                                                InputStream is = entity.getContent();
                                                
                                                String text = Tools.getTextFromStream(is);
                                                
                                                //發(fā)送消息化撕,讓主線程刷新UI
                                                Message msg = handler.obtainMessage();
                                                msg.obj = text;
                                                handler.sendMessage(msg);
                                        }
                                } catch (Exception e) {
                                        e.printStackTrace();
                                }
                        }
                };
                t.start();
        }
}

添加權限:

img

點擊get登陸按鈕几晤,運行結果:

img

2. 使用HttpClient發(fā)送post請求

src/cn.itcast.postmethod/MainActivity.java

package cn.itcast.postmethod;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import cn.itcast.getmethod.R;
import cn.itcast.getmethod.tool.Tools;

public class MainActivity extends Activity {

        Handler handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                        Toast.makeText(MainActivity.this, (String)msg.obj, 0).show();
                }
        };
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        }
        
        public void click2(View v){
                
                EditText et_name = (EditText)findViewById(R.id.et_name);
                EditText et_pass = (EditText)findViewById(R.id.et_pass);
                
                final String name = et_name.getText().toString();
                final String pass = et_pass.getText().toString();
                
                final String path = "http://:8080/Web/servlet/Login";
                
                Thread t = new Thread(){
                        @Override
                        public void run() {
                                //1. 創(chuàng)建客戶端對象
                                HttpClient client = new DefaultHttpClient();
                                
                                //2. 創(chuàng)建Http POST請求對象
                                HttpPost post = new HttpPost(path);
                                
                                try{
                                        //通過此集合封裝要提交的數(shù)據(jù)
                                        List<NameValuePair> parameters = new ArrayList<NameValuePair>();
                                        
                                        //集合的泛型是BasicNameValuePair類型,那么由此可以推算出植阴,要提交的數(shù)據(jù)是封裝在BasicNameValuePair對象中
                                        BasicNameValuePair bvp1 = new BasicNameValuePair("name", name);
                                        BasicNameValuePair bvp2 = new BasicNameValuePair("pass", pass);
                                        
                                        parameters.add(bvp1);
                                        parameters.add(bvp2);
                                        
                                        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters,"utf-8");
                                        //把實體類封裝至post請求中蟹瘾,提交post請求時,實體中的數(shù)據(jù)就會用輸出流寫給服務器
                                        post.setEntity(entity);
                                        
                                        //客戶端發(fā)送post請求
                                        HttpResponse response = client.execute(post);
                                        
                                        //獲取狀態(tài)行
                                       StatusLine line = response.getStatusLine();
                                       //從狀態(tài)行中拿到狀態(tài)碼
                                       if(line.getStatusCode() == 200){
                                              //獲取實體掠手,實體里存放的是服務器返回的數(shù)據(jù)的相關信息
                                               HttpEntity et = response.getEntity();
                                               //獲取服務器返回的輸入流
                                               InputStream is = et.getContent();
                            
                                               String text = Tools.getTextFromStream(is);
                            
                                               //發(fā)送消息憾朴,讓主線程刷新UI
                                               Message msg = handler.obtainMessage();
                                               msg.obj = text;
                                              handler.sendMessage(msg);
                                      }
                                } catch (Exception e) {
                                        e.printStackTrace();
                                }
                        }
                };
                t.start();
        }
}

點擊post登陸按鈕,運行結果:

img

3. 異步HttpClient框架

從github上下載android-async-http-master開源jar包喷鸽,拷貝library/src/main/java目錄下的內容到我們自己的項目中众雷。

img
img

拷貝后,發(fā)現(xiàn)有錯誤魁衙,這是由于Base64.java中的BuildConfig類導包問題报腔,Ctrl+Shift+O自動導包即可修復株搔。


img
img
img

使用異步HttpClient框架實現(xiàn)上面示例中的功能剖淀,activity.xml與上面的示例相同,修改MainActivity.java代碼纤房。
src/cn.itcast.asynchttpclient/MainActivity.java

package cn.itcast.asynchttpclient;

import org.apache.http.Header;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;

public class MainActivity extends Activity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        }
        
        public void click1(View v){
                
                EditText et_name = (EditText)findViewById(R.id.et_name);
                EditText et_pass = (EditText)findViewById(R.id.et_pass);
                
                final String name = et_name.getText().toString();
                final String pass = et_pass.getText().toString();
                
                final String path = "http://192.168.1.100:8080/Web/servlet/Login";
                
                //使用異步HttpClient發(fā)送get請求
                AsyncHttpClient client = new AsyncHttpClient();
                
                //定義一個請求參數(shù)對象纵隔,封裝要提交的數(shù)據(jù)
                RequestParams rp = new RequestParams();
                rp.add("name", name);
                rp.add("pass", pass);
                
                //發(fā)送get請求
                client.get(path, rp, new MyResponseHandler());
        }
        
        public void click2(View v){
                EditText et_name = (EditText)findViewById(R.id.et_name);
                EditText et_pass = (EditText)findViewById(R.id.et_pass);
                
                final String name = et_name.getText().toString();
                final String pass = et_pass.getText().toString();
                
                final String path = "http://192.168.1.100:8080/Web/servlet/Login";
                
                AsyncHttpClient client = new AsyncHttpClient();
                
                RequestParams rp = new RequestParams();
                rp.add("name", name);
                rp.add("pass", pass);
                
                //發(fā)送post請求
                client.post(path, rp, new MyResponseHandler());
        }
        
        class MyResponseHandler extends AsyncHttpResponseHandler{

                //請求成功時(響應碼為200開頭),此方法調用
                //登陸成功或者登錄失敗,只要請求成功捌刮,都會調用onSuccess方法
                @Override
                public void onSuccess(int statusCode, Header[] headers,
                                byte[] responseBody) {
                        Toast.makeText(MainActivity.this, new String(responseBody), 0).show();
                }

                //請求失敗時(響應碼非200開頭)調用
                @Override
                public void onFailure(int statusCode, Header[] headers,
                                byte[] responseBody, Throwable error) {
                        //請求不成功碰煌,也顯示登錄失敗
                        Toast.makeText(MainActivity.this, "登陸失敗", 0).show();
                }
        }
}

添加權限:

img

運行結果:分別點擊“get登陸”和“post登陸”按鈕。

img

4. 多線程下載的原理和過程

斷點續(xù)傳:上次下載到哪绅作,這次就從哪開始下芦圾。
多線程:下載速度更快。
原理:搶占服務器資源俄认。例如:帶寬為20M/s个少,3個人去下載同一部電影,那么每人分別占6.66M/s帶寬眯杏。如果有一人A開了3個線程同時下載夜焦,那么5個線程,各占4M/s帶寬岂贩,那么A所占帶寬就是4*3=12M/s茫经,其他兩人各占4M/s帶寬。也就是說A搶占了更多的服務器資源萎津。

img

多線程下載示例說明:
例如有一個10KB的文件卸伞,分成010,3個線程去下載,第0個線程下載02择镇,也就是3KB數(shù)據(jù)夹囚,第1個線程下載35,也就是3KB數(shù)據(jù)弃酌,余下的69,4KB的數(shù)據(jù)由最后一個線程下載儡炼。

總結出公式就是:
每個線程下載的數(shù)據(jù)開始點:threadId*size妓湘,結束點:(threadId + 1) * size -1。

最后一個線程除外乌询,下載結束點:length - 1榜贴。

計算每條線程的下載區(qū)間

多線程斷點續(xù)傳的API全部都是Java API,Java項目測試比較容易妹田,所以唬党,我們先創(chuàng)建一個Java項目。
將待下載的資源放入Tomcat服務器中鬼佣。

img
img

src/cn.itcast.MultiDownLoad/Main.java

package cn.itcast.MultiDownLoad;

import java.net.HttpURLConnection;
import java.net.URL;

public class Main {

        static int threadCount = 3;
        static String path = "http://localhost:8080/QQPlayer.exe";
        
        public static void main(String[] args) {
                URL url;
                try {
                        url = new URL(path);
                        
                        //打開連接對象驶拱,做初始化設置
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        
                        if(conn.getResponseCode() == 200){
                                //獲取要下載的目標文件的總長度
                                int length = conn.getContentLength();
                                
                                //計算每條線程要下載的長度
                                int size = length / threadCount;
                                System.out.println("size:" + size);

                                //計算每條線程下載的開始位置和結束位置
                                for(int threadId = 0; threadId < threadCount; threadId++){
                                        int startIndex = threadId * size;
                                        int endIndex = (threadId + 1) * size - 1;
                                        
                                        //如果是最后一條線程,那么需要把余數(shù)也一塊下載
                                        if(threadId == threadCount - 1){
                                                endIndex = length - 1;
                                        }
                                        System.out.println("線程" + threadId + "晶衷,下載區(qū)間為:" + startIndex + "-" + endIndex);
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
}

運行結果:

img

創(chuàng)建臨時文件
src/cn.itcast.MultiDownLoad/Main.java

package cn.itcast.MultiDownLoad;

import java.io.File;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {

        static int threadCount = 3;
        static String path = "http://localhost:8080/QQPlayer.exe";
        
        public static void main(String[] args) {
                URL url;
                try {
                        url = new URL(path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        
                        if(conn.getResponseCode() == 200){
                                int length = conn.getContentLength();
                                
                                int size = length / threadCount;
                                System.out.println("size:" + size);

                                //創(chuàng)建一個與目標文件大小一致的臨時文件
                                File file = new File(getFileNameFromPath(path));
                                //打開文件的訪問模式設置為rwd蓝纲,表示除了讀取和寫入阴孟,還要求對文件內容的每個更新都同步寫入到底層存儲設備。
                                //設計到下載的程序税迷,文件訪問模式一定要使用rwd永丝,不經過緩沖區(qū),直接寫入硬盤箭养。
                                //如果下載到的數(shù)據(jù)讓寫入到緩沖區(qū)慕嚷,一旦斷電,緩沖區(qū)數(shù)據(jù)丟失毕泌,并且下次服務器斷點續(xù)傳也不會再傳輸這部分數(shù)據(jù)闯冷,那么下載的文件就不能用了
                                RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                //設置臨時文件的大小
                                raf.setLength(length);
                                
                                for(int threadId = 0; threadId < threadCount; threadId++){
                                        int startIndex = threadId * size;
                                        int endIndex = (threadId + 1) * size - 1;
                                        
                                        if(threadId == threadCount - 1){
                                                endIndex = length - 1;
                                        }
                                        System.out.println("線程" + threadId + ",下載區(qū)間為:" + startIndex + "-" + endIndex);
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
        
        public static String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
}

開啟多個線程下載文件

src/cn.itcast.MultiDownLoad/Main.java

package cn.itcast.MultiDownLoad;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {

        static int threadCount = 3;
        static String path = "http://localhost:8080/QQPlayer.exe";
        
        public static void main(String[] args) {
                URL url;
                try {
                        url = new URL(path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        
                        if(conn.getResponseCode() == 200){
                                int length = conn.getContentLength();
                                
                                int size = length / threadCount;
                                System.out.println("size:" + size);

                                for(int threadId = 0; threadId < threadCount; threadId++){
                                        int startIndex = threadId * size;
                                        int endIndex = (threadId + 1) * size - 1;
                                        
                                        if(threadId == threadCount - 1){
                                                endIndex = length - 1;
                                        }
                                        System.out.println("線程" + threadId + "懈词,下載區(qū)間為:" + startIndex + "-" + endIndex);
                                        
                                        DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                        dt.start();
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
        
        public static String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
}

class DownLoadThread extends Thread{
        int threadId;
        int startIndex;
        int endIndex;
        
        public DownLoadThread(int threadId, int startIndex, int endIndex) {
                super();
                this.threadId = threadId;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
        }
        
        public void run(){
                URL url;
                try{
                        url = new URL(Main.path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        //Range表示指定請求的數(shù)據(jù)區(qū)間
                        conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                        
                        //請求部分數(shù)據(jù)蛇耀,返回的是206
                        if(conn.getResponseCode() == 206){
                                InputStream is = conn.getInputStream();
                                
                                //打開臨時文件的IO流
                                File file = new File(Main.getFileNameFromPath(Main.path));
                                RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                //修改寫入臨時文件的開始位置
                                raf.seek(startIndex);
                                
                                byte[] b = new byte[1024];
                                int len = 0;
                                //當前線程下載的總進度
                                int total = 0;
                                while((len = is.read(b)) != -1){
                                        //把讀取到的字節(jié)寫入臨時文件中
                                        raf.write(b, 0, len);
                                        total += len;
                                        System.out.println("線程" + threadId + "下載的進度為:" + total);
                                }
                                raf.close();
                        }
                        System.out.println("線程" + threadId + "下載完畢---------------------");
                }catch(Exception e){
                        e.printStackTrace();
                }
        }
}

運行結果:刷新,即可看到文件已經下載好了

img
img
img
img

創(chuàng)建進度臨時文件保存下載進度

src/cn.itcast.MultiDownLoad/Main.java

package cn.itcast.MultiDownLoad;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {

        static int threadCount = 3;
        static String path = "http://localhost:8080/QQPlayer.exe";
        
        public static void main(String[] args) {
                URL url;
                try {
                        url = new URL(path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        
                        if(conn.getResponseCode() == 200){
                                int length = conn.getContentLength();
                                
                                int size = length / threadCount;
                                System.out.println("size:" + size);

                                for(int threadId = 0; threadId < threadCount; threadId++){
                                        int startIndex = threadId * size;
                                        int endIndex = (threadId + 1) * size - 1;
                                        
                                        if(threadId == threadCount - 1){
                                                endIndex = length - 1;
                                        }
                                        System.out.println("線程" + threadId + "坎弯,下載區(qū)間為:" + startIndex + "-" + endIndex);
                                        
                                        DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                        dt.start();
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
        
        public static String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
}

class DownLoadThread extends Thread{
        int threadId;
        int startIndex;
        int endIndex;
        
        public DownLoadThread(int threadId, int startIndex, int endIndex) {
                super();
                this.threadId = threadId;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
        }
        
        public void run(){
                URL url;
                try{
                        url = new URL(Main.path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                        
                        if(conn.getResponseCode() == 206){
                                InputStream is = conn.getInputStream();
                                
                                File file = new File(Main.getFileNameFromPath(Main.path));
                                RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                raf.seek(startIndex);
                                
                                byte[] b = new byte[1024];
                                int len = 0;
                                int total = 0;
                                while((len = is.read(b)) != -1){
                                        raf.write(b, 0, len);
                                        total += len;
                                        System.out.println("線程" + threadId + "下載的進度為:" + total);
                                        
                                        //創(chuàng)建一個進度臨時文件纺涤,保存下載進度
                                        File fileProgress = new File(threadId + ".txt");
                                        RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                                        rafProgress.write((total + "").getBytes());
                                        rafProgress.close();
                                }
                                raf.close();
                        }
                        System.out.println("線程" + threadId + "下載完畢---------------------");
                }catch(Exception e){
                        e.printStackTrace();
                }
        }
}

運行結果:執(zhí)行程序,然后抠忘,在沒下載完成時撩炊,就點擊右上角的停止按鈕。

img

刷新崎脉,可以看到記錄文件已經產生拧咳。

img
img

完成斷點續(xù)傳下載

src/cn.itcast.MultiDownLoad/Main.java

package cn.itcast.MultiDownLoad;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {

        static int threadCount = 3;
        static String path = "http://localhost:8080/QQPlayer.exe";
        
        public static void main(String[] args) {
                
                URL url;
                
                try {
                        url = new URL(path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        
                        if(conn.getResponseCode() == 200){
                                int length = conn.getContentLength();
                                
                                int size = length / threadCount;
                                System.out.println("size:" + size);

                                for(int threadId = 0; threadId < threadCount; threadId++){
                                        int startIndex = threadId * size;
                                        int endIndex = (threadId + 1) * size - 1;
                                        
                                        if(threadId == threadCount - 1){
                                                endIndex = length - 1;
                                        }
                                        DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                        dt.start();
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
        
        public static String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
}

class DownLoadThread extends Thread{
        int threadId;
        int startIndex;
        int endIndex;
        
        public DownLoadThread(int threadId, int startIndex, int endIndex) {
                super();
                this.threadId = threadId;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
        }
        
        public void run(){
                
                URL url;
                
                try{
                        int lastProgress = 0;
                        //下載之前,先判斷進度臨時文件是否存在
                        File fileProgress1 = new File(threadId + ".txt");
                        if(fileProgress1.exists()){
                                FileInputStream fis = new FileInputStream(fileProgress1);
                                BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                                //讀取進度臨時文件中的值
                                lastProgress = Integer.parseInt(br.readLine());
                                //把上一次下載的進度加到下載開始位置
                                startIndex += lastProgress;
                                fis.close();
                        }
                        
                        System.out.println("線程" + threadId + "囚灼,下載區(qū)間為:" + startIndex + "-" + endIndex);
                        
                        url = new URL(Main.path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                        
                        if(conn.getResponseCode() == 206){
                                InputStream is = conn.getInputStream();
                                
                                File file = new File(Main.getFileNameFromPath(Main.path));
                                RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                raf.seek(startIndex);
                                
                                byte[] b = new byte[1024];
                                int len = 0;
                                //從之前下載的地方開始下載
                                int total = lastProgress;
                                while((len = is.read(b)) != -1){
                                        raf.write(b, 0, len);
                                        total += len;
                                        System.out.println("線程" + threadId + "下載的進度為:" + total);
                                        
                                        File fileProgress = new File(threadId + ".txt");
                                        RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                                        rafProgress.write((total + "").getBytes());
                                        rafProgress.close();
                                }
                                raf.close();
                                System.out.println("線程" + threadId + "下載完畢---------------------");
                        }
                }catch(Exception e){
                        e.printStackTrace();
                }
        }
}

運行結果:

執(zhí)行Main.java程序骆膝,然后,在還沒有下載完灶体,停止阅签。然后,再次執(zhí)行Main.java蝎抽,可以看到如下顯示政钟,也就是實現(xiàn)了斷點續(xù)傳。

img

下載后刪除進度臨時文件
src/cn.itcast.MultiDownLoad/Main.java

package cn.itcast.MultiDownLoad;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {

        //記錄當前已經下載完成的線程的數(shù)量
        static int finishedThreadCount = 0;
        static int threadCount = 3;
        static String path = "http://localhost:8080/QQPlayer.exe";
        
        public static void main(String[] args) {
                
                URL url;
                
                try {
                        url = new URL(path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        
                        if(conn.getResponseCode() == 200){
                                int length = conn.getContentLength();
                                
                                int size = length / threadCount;
                                System.out.println("size:" + size);

                                for(int threadId = 0; threadId < threadCount; threadId++){
                                        int startIndex = threadId * size;
                                        int endIndex = (threadId + 1) * size - 1;
                                        
                                        if(threadId == threadCount - 1){
                                                endIndex = length - 1;
                                        }
                                        DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                        dt.start();
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
        
        public static String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
}

class DownLoadThread extends Thread{
        int threadId;
        int startIndex;
        int endIndex;
        
        public DownLoadThread(int threadId, int startIndex, int endIndex) {
                super();
                this.threadId = threadId;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
        }
        
        public void run(){
                
                URL url;
                
                try{
                        int lastProgress = 0;
                        File fileProgress1 = new File(threadId + ".txt");
                        if(fileProgress1.exists()){
                                FileInputStream fis = new FileInputStream(fileProgress1);
                                BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                                lastProgress = Integer.parseInt(br.readLine());
                                startIndex += lastProgress;
                                fis.close();
                        }
                        
                        System.out.println("線程" + threadId + "樟结,下載區(qū)間為:" + startIndex + "-" + endIndex);
                        
                        url = new URL(Main.path);
                        
                        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                        conn.setConnectTimeout(8000);
                        conn.setReadTimeout(8000);
                        conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                        
                        if(conn.getResponseCode() == 206){
                                InputStream is = conn.getInputStream();
                                
                                File file = new File(Main.getFileNameFromPath(Main.path));
                                RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                raf.seek(startIndex);
                                
                                byte[] b = new byte[1024];
                                int len = 0;
                                int total = lastProgress;
                                while((len = is.read(b)) != -1){
                                        raf.write(b, 0, len);
                                        total += len;
                                        System.out.println("線程" + threadId + "下載的進度為:" + total);
                                        
                                        File fileProgress = new File(threadId + ".txt");
                                        RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                                        rafProgress.write((total + "").getBytes());
                                        rafProgress.close();
                                }
                                raf.close();
                                System.out.println("線程" + threadId + "下載完畢---------------------");
                                
                                //在所有線程都下載完畢后养交,一起刪除所有進度臨時文件
                                //有一個線程完成下載,已經下載完成的線程的數(shù)量+1
                                Main.finishedThreadCount++;

                                synchronized(Main.path){
                                        if(Main.finishedThreadCount == 3){
                                                //刪除所有進度臨時文件
                                                for(int i = 0; i < Main.finishedThreadCount; i++){
                                                        File f = new File(i + ".txt");
                                                        f.delete();
                                                }
                                                //為了防止所有線程都執(zhí)行到上面的Main.finishedThreadCount++;瓢宦,然后三個線程都執(zhí)行刪除所有臨時文件的代碼碎连。
                                                //所以,一方面使用同步代碼塊刁笙,另一方面將Main.finishedThreadCount設置為0破花。
                                                Main.finishedThreadCount = 0;
                                        }
                                }
                        }
                }catch(Exception e){
                        e.printStackTrace();
                }
        }
}

運行結果:運行Main.java,斷點續(xù)傳完成后疲吸,刷新座每。可以看到摘悴,臨時文件已經被刪除峭梳。

img

5. Android版多線程斷點續(xù)傳下載

res/layout/activity.xml

<RelativeLayout 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"
    tools:context=".MainActivity" >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下載"
        android:onClick="click" />

</RelativeLayout>

src/cn.itcast.androidmultidownload/MainActivity.xml

package cn.itcast.androidmultidownload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;

public class MainActivity extends Activity {

        int finishedThreadCount = 0;
        int threadCount = 3;
        String path = "http://192.168.1.100:8080/QQPlayer.exe";
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        }

    public void click(View v){
            Thread t = new Thread(){
                    @Override
                    public void run() {

                            URL url;
                            
                            try {
                                    url = new URL(path);
                                    
                                    HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                                    conn.setConnectTimeout(8000);
                                    conn.setReadTimeout(8000);
                                    
                                    if(conn.getResponseCode() == 200){
                                            int length = conn.getContentLength();
                                            
                                            int size = length / threadCount;
                                            System.out.println("size:" + size);

                                            for(int threadId = 0; threadId < threadCount; threadId++){
                                                    int startIndex = threadId * size;
                                                    int endIndex = (threadId + 1) * size - 1;
                                                    
                                                    if(threadId == threadCount - 1){
                                                            endIndex = length - 1;
                                                    }
                                                    DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                                    dt.start();
                                            }
                                    }
                            } catch (Exception e) {
                                    e.printStackTrace();
                            }
                    }
            };
            t.start();
    }
    
        public String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
        
        class DownLoadThread extends Thread{
                int threadId;
                int startIndex;
                int endIndex;
                
                public DownLoadThread(int threadId, int startIndex, int endIndex) {
                        super();
                        this.threadId = threadId;
                        this.startIndex = startIndex;
                        this.endIndex = endIndex;
                }
                
                public void run(){
                        
                        URL url;
                        
                        try{
                                int lastProgress = 0;
                                //修改文件路徑,存在外部存儲器中
                                File fileProgress1 = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                                if(fileProgress1.exists()){
                                        FileInputStream fis = new FileInputStream(fileProgress1);
                                        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                                        lastProgress = Integer.parseInt(br.readLine());
                                        startIndex += lastProgress;
                                        fis.close();
                                }
                                
                                System.out.println("線程" + threadId + "蹂喻,下載區(qū)間為:" + startIndex + "-" + endIndex);
                                
                                url = new URL(path);
                                
                                HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                                conn.setConnectTimeout(8000);
                                conn.setReadTimeout(8000);
                                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                                
                                if(conn.getResponseCode() == 206){
                                        InputStream is = conn.getInputStream();
                                        
                                        File file = new File(Environment.getExternalStorageDirectory(), getFileNameFromPath(path));
                                        RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                        raf.seek(startIndex);
                                        
                                        byte[] b = new byte[1024];
                                        int len = 0;
                                        int total = lastProgress;
                                        while((len = is.read(b)) != -1){
                                                raf.write(b, 0, len);
                                                total += len;
                                                System.out.println("線程" + threadId + "下載的進度為:" + total);
                                                
                                                File fileProgress = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                                                RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                                                rafProgress.write((total + "").getBytes());
                                                rafProgress.close();
                                        }
                                        raf.close();
                                        System.out.println("線程" + threadId + "下載完畢---------------------");
                                        
                                        finishedThreadCount++;

                                        synchronized(path){
                                                if(finishedThreadCount == 3){
                                                        for(int i = 0; i < finishedThreadCount; i++){
                                                                File f = new File(Environment.getExternalStorageDirectory(), i + ".txt");
                                                                f.delete();
                                                        }
                                                        finishedThreadCount = 0;
                                                }
                                        }
                                }
                        }catch(Exception e){
                                e.printStackTrace();
                        }
                }
        }
}

添加權限:


img

運行結果:點擊“下載”按鈕葱椭,在下載完成之前,殺死線程口四。

img
img

可以看到臨時文件生成孵运。


img
img

再次運行應用程序,點擊“下載”按鈕蔓彩,接著下載治笨,斷點續(xù)傳成功實現(xiàn)。

img

下載完成后赤嚼,可以看到臨時文件刪除成功旷赖。

img

添加進度條反應下載進度,res/layout/activity.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"
    tools:context=".MainActivity" 
    android:orientation="vertical">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下載"
        android:onClick="click" />

    <ProgressBar 
        android:id="@+id/pb"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />
    
</LinearLayout>

src/cn.itcast.androidmultidownload/MainActivity.xml

package cn.itcast.androidmultidownload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.ProgressBar;

public class MainActivity extends Activity {

        int finishedThreadCount = 0;
        int threadCount = 3;
        String path = "http://192.168.1.100:8080/QQPlayer.exe";
        
        private ProgressBar pb;
        //記錄進度條的當前進度
        int currentProgress = 0;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                
                //進度條
                pb = (ProgressBar) findViewById(R.id.pb);
        }

    public void click(View v){
            Thread t = new Thread(){
                    @Override
                    public void run() {

                            URL url;
                            
                            try {
                                    url = new URL(path);
                                    
                                    HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                                    conn.setConnectTimeout(8000);
                                    conn.setReadTimeout(8000);
                                    
                                    if(conn.getResponseCode() == 200){
                                            int length = conn.getContentLength();
                                            
                                            //設定進度條的最大值
                                            pb.setMax(length);
                                            
                                            int size = length / threadCount;
                                            System.out.println("size:" + size);

                                            for(int threadId = 0; threadId < threadCount; threadId++){
                                                    int startIndex = threadId * size;
                                                    int endIndex = (threadId + 1) * size - 1;
                                                    
                                                    if(threadId == threadCount - 1){
                                                            endIndex = length - 1;
                                                    }
                                                    DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                                    dt.start();
                                            }
                                    }
                            } catch (Exception e) {
                                    e.printStackTrace();
                            }
                    }
            };
            t.start();
    }
    
        public String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
        
        class DownLoadThread extends Thread{
                int threadId;
                int startIndex;
                int endIndex;
                
                public DownLoadThread(int threadId, int startIndex, int endIndex) {
                        super();
                        this.threadId = threadId;
                        this.startIndex = startIndex;
                        this.endIndex = endIndex;
                }
                
                public void run(){
                        
                        URL url;
                        
                        try{
                                int lastProgress = 0;
                                File fileProgress1 = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                                if(fileProgress1.exists()){
                                        FileInputStream fis = new FileInputStream(fileProgress1);
                                        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                                        lastProgress = Integer.parseInt(br.readLine());
                                        startIndex += lastProgress;
                                        
                                        //如果開始位置大于或等于endIndex更卒,說明上一次下載中等孵,此線程就已經下載完了
                                        if(startIndex >= endIndex){
                                                finishedThreadCount++;
                                        }
                                        
                                        //如果上一次下載過,把上次的進度加到當前進度中
                                        currentProgress += lastProgress;
                                        pb.setProgress(currentProgress);
                                        fis.close();
                                }
                                
                                System.out.println("線程" + threadId + "蹂空,下載區(qū)間為:" + startIndex + "-" + endIndex);
                                
                                url = new URL(path);
                                
                                HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                                conn.setConnectTimeout(8000);
                                conn.setReadTimeout(8000);
                                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                                
                                if(conn.getResponseCode() == 206){
                                        InputStream is = conn.getInputStream();
                                        
                                        File file = new File(Environment.getExternalStorageDirectory(), getFileNameFromPath(path));
                                        RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                        raf.seek(startIndex);
                                        
                                        byte[] b = new byte[1024];
                                        int len = 0;
                                        int total = lastProgress;
                                        while((len = is.read(b)) != -1){
                                                raf.write(b, 0, len);
                                                total += len;
                                                
                                                System.out.println("線程" + threadId + "下載的進度為:" + total);
                                                
                                                File fileProgress = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                                                RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                                                rafProgress.write((total + "").getBytes());
                                                rafProgress.close();
                                                
                                                //每一條線程下載的數(shù)據(jù)俯萌,都應該加到全局進度里
                                                currentProgress += len;
                                                //設置進度條當前進度
                                                //進度條內部也是通過handler讓主線程刷新UI的
                                                pb.setProgress(currentProgress);
                                        }
                                        raf.close();
                                        System.out.println("線程" + threadId + "下載完畢---------------------");
                                        
                                        finishedThreadCount++;

                                        synchronized(path){
                                                if(finishedThreadCount == 3){
                                                        for(int i = 0; i < finishedThreadCount; i++){
                                                                File f = new File(Environment.getExternalStorageDirectory(), i + ".txt");
                                                                f.delete();
                                                        }
                                                        finishedThreadCount = 0;
                                                }
                                        }
                                }
                        }catch(Exception e){
                                e.printStackTrace();
                        }
                }
        }
}

運行結果:點擊“下載”按鈕,可以通過進度條看到下載進度上枕。然后绳瘟,殺死進程,再重新運行應用程序姿骏,點擊“下載”按鈕糖声,可以看到進度條在原有的基礎上繼續(xù)向前移動,也就是實現(xiàn)了斷點續(xù)傳的進度條實現(xiàn)分瘦。

img

添加文本進度蘸泻,res/layout/activity.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"
    tools:context=".MainActivity" 
    android:orientation="vertical">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下載"
        android:onClick="click" />

    <ProgressBar 
        android:id="@+id/pb"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />
    
    <TextView 
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0%"
        android:layout_gravity="right"
        />
    
</LinearLayout>

src/cn.itcast.androidmultidownload/MainActivity.xml

package cn.itcast.androidmultidownload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {

        int finishedThreadCount = 0;
        int threadCount = 3;
        String path = "http://192.168.1.100:8080/QQPlayer.exe";
        
        private ProgressBar pb;
        int currentProgress = 0;
        
        private TextView tv;
        
        //刷新TextView
        Handler handler = new Handler(){
                public void handleMessage(android.os.Message msg) {
                        //當前進度除以最大進度,得到下載進度的百分比
                        tv.setText(pb.getProgress() * 100 /pb.getMax() + "%");
                }
        };
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                
                pb = (ProgressBar) findViewById(R.id.pb);
                tv = (TextView)findViewById(R.id.tv);
        }

    public void click(View v){
            Thread t = new Thread(){
                    @Override
                    public void run() {

                            URL url;
                            
                            try {
                                    url = new URL(path);
                                    
                                    HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                                    conn.setConnectTimeout(8000);
                                    conn.setReadTimeout(8000);
                                    
                                    if(conn.getResponseCode() == 200){
                                            int length = conn.getContentLength();
                                            
                                            pb.setMax(length);
                                            
                                            int size = length / threadCount;
                                            System.out.println("size:" + size);

                                            for(int threadId = 0; threadId < threadCount; threadId++){
                                                    int startIndex = threadId * size;
                                                    int endIndex = (threadId + 1) * size - 1;
                                                    
                                                    if(threadId == threadCount - 1){
                                                            endIndex = length - 1;
                                                    }
                                                    DownLoadThread dt = new DownLoadThread(threadId, startIndex, endIndex);
                                                    dt.start();
                                            }
                                    }
                            } catch (Exception e) {
                                    e.printStackTrace();
                            }
                    }
            };
            t.start();
    }
    
        public String getFileNameFromPath(String path){
                int index = path.lastIndexOf("/");
                return path.substring(index + 1);
        }
        
        class DownLoadThread extends Thread{
                int threadId;
                int startIndex;
                int endIndex;
                
                public DownLoadThread(int threadId, int startIndex, int endIndex) {
                        super();
                        this.threadId = threadId;
                        this.startIndex = startIndex;
                        this.endIndex = endIndex;
                }
                
                public void run(){
                        
                        URL url;
                        
                        try{
                                int lastProgress = 0;
                                File fileProgress1 = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                                if(fileProgress1.exists()){
                                        FileInputStream fis = new FileInputStream(fileProgress1);
                                        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                                        lastProgress = Integer.parseInt(br.readLine());
                                        startIndex += lastProgress;
                                        
                                        if(startIndex >= endIndex){
                                                finishedThreadCount++;
                                        }
                                        
                                        currentProgress += lastProgress;
                                        pb.setProgress(currentProgress);
                                        
                                        //發(fā)送消息嘲玫,讓主線程刷新文本進度
                                        handler.sendEmptyMessage(1);
                                        fis.close();
                                }
                                
                                System.out.println("線程" + threadId + "悦施,下載區(qū)間為:" + startIndex + "-" + endIndex);
                                
                                url = new URL(path);
                                
                                HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                                conn.setConnectTimeout(8000);
                                conn.setReadTimeout(8000);
                                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                                
                                if(conn.getResponseCode() == 206){
                                        InputStream is = conn.getInputStream();
                                        
                                        File file = new File(Environment.getExternalStorageDirectory(), getFileNameFromPath(path));
                                        RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                                        raf.seek(startIndex);
                                        
                                        byte[] b = new byte[1024];
                                        int len = 0;
                                        int total = lastProgress;
                                        while((len = is.read(b)) != -1){
                                                raf.write(b, 0, len);
                                                total += len;
                                                
                                                System.out.println("線程" + threadId + "下載的進度為:" + total);
                                                
                                                File fileProgress = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                                                RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                                                rafProgress.write((total + "").getBytes());
                                                rafProgress.close();
                                                
                                                currentProgress += len;
                                                pb.setProgress(currentProgress);
                                                
                                                //發(fā)送消息,讓主線程刷新文本進度
                                                handler.sendEmptyMessage(1);
                                        }
                                        raf.close();
                                        System.out.println("線程" + threadId + "下載完畢---------------------");
                                        
                                        finishedThreadCount++;

                                        synchronized(path){
                                                if(finishedThreadCount == 3){
                                                        for(int i = 0; i < finishedThreadCount; i++){
                                                                File f = new File(Environment.getExternalStorageDirectory(), i + ".txt");
                                                                f.delete();
                                                        }
                                                        finishedThreadCount = 0;
                                                }
                                        }
                                }
                        }catch(Exception e){
                                e.printStackTrace();
                        }
                }
        }
}

運行結果:

img

文本進度計算的bug:當文件較大時去团,就會出現(xiàn)bug抡诞,文本進度計算數(shù)據(jù)變成了負數(shù)穷蛹。

img

這是因為文件大小超出了int所能表示的最大范圍。

img

只需要修改代碼如下即可昼汗。

img

如果最終顯示為99%肴熏,那么只需要在下載完成之后,直接在程序中寫死為100%即可顷窒。

6. xUtils多線程斷點續(xù)傳下載

從github上下載xUtils蛙吏,將xUtils的jar復制到libs目錄下。

img
img

如果無法關聯(lián)源碼鞋吉,可以通過在libs目錄下新建一個properties文件解決鸦做。

img

properties文件的內容為"src=源碼目錄",即可成功關聯(lián)源碼谓着。

img

res/layout/activity.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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" 
    android:orientation="vertical"
    >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下載"
        android:onClick="click" />
    
    <TextView 
            android:id="@+id/tv_success"
            android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    />
    
    <TextView 
            android:id="@+id/tv_failure"
            android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#ff0000"
    />
    
    <ProgressBar 
            android:id="@+id/tv_pb"
            style="@android:style/Widget.ProgressBar.Horizontal"
            android:layout_width="match_parent"
        android:layout_height="wrap_content"
    />

    <TextView 
            android:id="@+id/tv_progress"
            android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    />
</LinearLayout>

src/cn.itcast.androidmultidownload/MainActivity.xml

package cn.itcast.xutils;

import java.io.File;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.HttpHandler;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;

public class MainActivity extends Activity {

        String path = "http://192.168.1.100:8080/QQPlayer.exe";
        
        private TextView tv;
        private ProgressBar pb;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                
                pb = (ProgressBar)findViewById(R.id.tv_pb);
                tv = (TextView)findViewById(R.id.tv_progress);
        }

    public void click(View v){
            HttpUtils utils = new HttpUtils();
            
            HttpHandler handler = utils.download(path, //請求的網(wǎng)址
                            "sdcard/QQPlayer.exe", //文件保存的路徑及文件名
                        true, // 是否支持斷點續(xù)傳
                        true, // 如果相應頭中包含文件名泼诱,那么下載完畢后,自動以該名字重命名文件
                        new RequestCallBack<File>() {
                    
                                    //下載完成調用
                            @Override
                            public void onSuccess(ResponseInfo<File> responseInfo) {
                                    TextView tv = (TextView)findViewById(R.id.tv_success);
                                    tv.setText(responseInfo.result.getPath());
                            }

                            //下載失敗后調用
                            @Override
                            public void onFailure(HttpException error, String msg) {
                                    TextView tv = (TextView)findViewById(R.id.tv_success);
                                    tv.setText(msg);
                            }
                            
                            //下載過程中不斷調用
                            @Override
                                    public void onLoading(long total, long current,
                                                    boolean isUploading) {
                                    pb.setMax((int)total);
                                    pb.setProgress((int)current);
                                    tv.setText((current * 100)/ total + "%");
                                    }
                    });
    }
}

添加權限:

img

運行結果:

img
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末赊锚,一起剝皮案震驚了整個濱河市坷檩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌改抡,老刑警劉巖矢炼,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異阿纤,居然都是意外死亡句灌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門欠拾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胰锌,“玉大人,你說我怎么就攤上這事藐窄∽拭粒” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵荆忍,是天一觀的道長格带。 經常有香客問我,道長刹枉,這世上最難降的妖魔是什么叽唱? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮微宝,結果婚禮上棺亭,老公的妹妹穿的比我還像新娘。我一直安慰自己蟋软,他們只是感情好镶摘,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布嗽桩。 她就那樣靜靜地躺著,像睡著了一般凄敢。 火紅的嫁衣襯著肌膚如雪碌冶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天贡未,我揣著相機與錄音,去河邊找鬼蒙袍。 笑死俊卤,一個胖子當著我的面吹牛,可吹牛的內容都是我干的害幅。 我是一名探鬼主播消恍,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼以现!你這毒婦竟也來了狠怨?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤邑遏,失蹤者是張志新(化名)和其女友劉穎佣赖,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體记盒,經...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡憎蛤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了纪吮。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俩檬。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖碾盟,靈堂內的尸體忽然破棺而出棚辽,到底是詐尸還是另有隱情,我是刑警寧澤冰肴,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布屈藐,位于F島的核電站,受9級特大地震影響熙尉,放射性物質發(fā)生泄漏估盘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一骡尽、第九天 我趴在偏房一處隱蔽的房頂上張望遣妥。 院中可真熱鬧,春花似錦攀细、人聲如沸箫踩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽境钟。三九已至锦担,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間慨削,已是汗流浹背洞渔。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缚态,地道東北人磁椒。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像玫芦,于是被迫代替她去往敵國和親浆熔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,117評論 25 707
  • 一.DownloadManager的介紹 1.Android涉及到的網(wǎng)絡數(shù)據(jù)請求桥帆,如果是零星數(shù)據(jù)医增、且數(shù)據(jù)量較小(...
    少年的大叔心閱讀 2,229評論 0 5
  • 每天都是度日如年老虫,還沒畢業(yè)就要背負每月1645元的貸款叶骨,只好離校找工作,但是處處碰壁祈匙,沒有一家要我邓萨,每次只要技術有...
    心暢密語閱讀 168評論 0 0
  • 背叛 是夜,燈火在闌珊菊卷,而A城的不夜城的生活才剛剛開始缔恳。 不夜城顧名思義一個沒有夜晚的地方。不夜城中有一家有名的夜...
    破曉的黎閱讀 506評論 0 0
  • 有一天,兩位黑幫老大扑眉,浩南哥和浩北哥被李Sir抓了起來纸泄。李Sir證據(jù)不足,便想出了一條妙計腰素。 他把兩位大佬分開關押...
    你看得見我閱讀 1,811評論 1 4