Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中的網絡編程

Android中的網絡編程

編輯:關於Android編程

一、訪問網絡資源 1、使用統一資源定位符獲取網絡資源的路徑url URL url = new URL(path);



2、通過url打開網絡連接(連接方式有http連接,ftp連接,https連接,rtsp連接)
此處獲取網絡連接用到的是http連接,所以使打開一個HttpURLConnection
   HttpURLConnection openConnection = (HttpConnection)url.openConnection();
   openConnection.setRequestMethod("GET");//設置請求方式
   openConnection.setConnectTimeout(5000);//設置請求超時時間  


3、打開連接後就可以獲取網絡返回的數據(例)
 String contentType = openConnection.getContentType();//獲取返回的數據類型
 Object content = openConnection.getContent();//獲取放回的數據
 int code = openConnection.getResponseCode();//獲取響應碼,200--返回正確,404--資源沒找到,503--服務器內部錯誤
 ......
4、獲取輸入流,保存返回的數據
InputStream inputStream = openConnection.getInputStream();
5、根據資源類型將網絡資源轉換成相應的資源,如是圖片資源,則如下轉換
Bitmap decodeStream = BitmapFactory.decodeStream(inputStream);
  6、訪問網絡需要添加網絡權限 7、一個常用的參數:User-Agent,我們可以通過這個參數來獲取這個資源的來源信息,如某個網站,iphone6 plus等 例:
openConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64;Trident/4.0;SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; InfoPath.2");
8、網絡路徑中不能包含中文,如果在路徑中需要涉及到中文,需要使用將中文使用URLEncoder對中文進行編碼
URLEncoder.encode("中文",utf-8);
  二、使用smartImageView加載網絡圖片 smartImageView繼承自ImageView,具有ImageView的所有功能,同時擴展了ImageVIew的功能,如常用的方法setImageUrl(URL url),這個方法可以通過直接傳遞圖片的URL地址來給smartImageView控件設置圖片。 smartIamgeView使用異步加載的方式從網絡獲取網絡圖片,加載過程在子線程中執行,在使用時只需要傳遞圖片的路徑即可,不需要在子線程訪問網絡和加載的問題。
public class MainActivity extends Activity {
    String path = "http://f.hiphotos.baidu.com/image/pic/item/a8014c086e061d9507500dd67ff40ad163d9cacd.jpg";
    private SmartImageView smiv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button bt = (Button) findViewById(R.id.bt);
        smiv = (SmartImageView) findViewById(R.id.smiv);
    }

    public void click(View v){
        smiv.setImageUrl(path);
    }
}
 
三、使用Get請求方式請求網絡 模擬QQ登錄
      1、服務器端代碼
 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //01010101
    String qq = request.getParameter("qq");//采用的編碼是iso-8859-1
    String pwd = request.getParameter("pwd");
    System.out.println("qq:"+new String(qq.getBytes("iso-8859-1"),"utf-8"));
    System.out.println("pwd:"+new String(pwd.getBytes("iso-8859-1"),"utf-8"));
    //查詢數據庫 看qq和密碼是否存在
    if("10000".equals(qq)&&"abcde".equals(pwd)){
        //tomcat容器如果發現字符串不識別就默認采用本地碼表
        response.getOutputStream().write("登陸成功".getBytes("utf-8"));
    }else{
        response.getOutputStream().write("登陸失敗".getBytes("utf-8"));
    }
}
 
服務器端會通過HttpServletRequestrequestgetParameter()方法獲取到用戶請求網絡的參數,如用戶名和密碼。用戶發送請求時,輸入的請求參數都會展示在地址欄,即地址欄的所有的參數就是服務器端要獲取到的所有參數。在發送請求時,只需要在請求地址後面加上相應的參數就能發送get請求,如www.qq.com/web/LogingServlet?qq=10000&pwd=abcde
 
2、客戶端在發送get請求時,需要將請求的參數傳遞到URL中,然後在發送請求。如:
//獲取請求的參數
final String qq = et_qq.getText().toString().trim();
final String pwd = et_pwd.getText().toString().trim();
//將參數添加到請求地址中
String path = "http://192.168.1.103:8080/web/LoginServlet?qq="+URLEncoder.encode(qq, "utf-8")+"&pwd="+URLEncoder.encode(pwd, "utf-8");
 
3、get請求的優缺點
優點:使用方便,只需要的地址後面組拼請求參數即可發送請求
缺點:(1)請求參數在地址欄都能展示出來,不安全;
(2)數據的長度有限制
 
四、使用post請求方式發送網絡請求 1、post請求方式的優缺點 優點:安全,數據不是在url後面組拼,而是通過流的形式寫給服務器;數據的長度沒有限制 缺點:編寫麻煩 2、post請求和get請求的區別 (1)get請求需要在URL後面組拼提交的數據,post請求不需要組拼任何數據 (2)post請求必須要指定請求提交的數據長度(如下圖,post請求比get請求多了Content-Type請求頭)\ (3)post請求是以流的方式吧數據寫給服務器,所有的http請求頭必須要告訴服務器寫多長的數據(如下圖,post請求比get請求多了Content-Length請求頭) 3、服務端代碼示例
 @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    System.out.println("post過來的請求");
    doGet(req, resp);
}
4、示例代碼
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//1.設置請求方式為POST
conn.setRequestMethod("POST"); //注意單詞必須大寫.
conn.setConnectTimeout(5000);
//2.設置http請求數據的類型為表單類型
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
//3.設置給服務器寫的數據的長度
//qq=10000&pwd=abcde
String data = "qq="+URLEncoder.encode(qq, "utf-8")+"&pwd="+URLEncoder.encode(pwd, "utf-8");
conn.setRequestProperty("Content-Length", String.valueOf(data.length()));
//4.記得指定要給服務器寫數據
conn.setDoOutput(true);
//5.開始向服務器寫數據
conn.getOutputStream().write(data.getBytes());
五、使用HTTPClient發送網絡請求 1、發送get請求
String path = "http://192.168.1.103:8080/web/LoginServlet?qq="+URLEncoder.encode(qq, "utf-8")+"&pwd="+URLEncoder.encode(pwd, "utf-8");
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(path);
HttpResponse response = client.execute(httpGet);
//獲取狀態碼
int code = response.getStatusLine().getStatusCode();  

if(code == 200){
    InputStream is = response.getEntity().getContent();
    String result = StreamTools.readStream(is);
    Message msg = Message.obtain();
    msg.what = SUCCESS;
    msg.obj = result;
    handler.sendMessage(msg);
}else{
    Message msg = Message.obtain();
    msg.what = ERROR;
    handler.sendMessage(msg);
}  
 String path = "http://192.168.1.103:8080/web/LoginServlet";
HttpClient client = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(path);
List parameters = new ArrayList();
parameters.add(new BasicNameValuePair("qq", qq));
parameters.add(new BasicNameValuePair("pwd", pwd));
httpPost.setEntity(new UrlEncodedFormEntity(parameters, "utf-8"));
HttpResponse response = client.execute(httpPost);
//獲取狀態碼
int code = response.getStatusLine().getStatusCode();

if(code == 200){
    InputStream is = response.getEntity().getContent();
    String result = StreamTools.readStream(is);
    Message msg = Message.obtain();
    msg.what = SUCCESS;
    msg.obj = result;
    handler.sendMessage(msg);
}else{
    Message msg = Message.obtain();
    msg.what = ERROR;
    handler.sendMessage(msg);
} 
 
StreamTools.readStream()
public class StreamTools {
    /**
     * 工具方法
     * @param is 輸入流
     * @return 文本字符串
     * @throws Exception
     */
    public static String readStream(InputStream is) throws Exception{
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = -1;
        while((len = is.read(buffer))!=-1){
            baos.write(buffer, 0, len);
        }
        is.close();
        String temp =  baos.toString();
        return temp;
    }
}
  六、使用過異步網絡加載框架AsyncHttpClient請求網絡 1、AsyncHttpClient進一步對HttpClient進行了封裝,這個框架考慮到了子線程問題,我們在使用時就不用再創建子線程,直接使用估計可,同時框架中還使用了線程池,使加載效率更高。   2、發送get請求
String path = "http://192.168.1.103:8080/web/LoginServlet?qq="+URLEncoder.encode(qq)+"&pwd="+URLEncoder.encode(pwd);
AsyncHttpClient client = new AsyncHttpClient();
client.get(path, new AsyncHttpResponseHandler() {
    @Override
    public void onSuccess(int statusCode, Header[] headers,
            byte[] responseBody) {
        tv_status.setText(new String(responseBody));
    }
    @Override
    public void onFailure(int statusCode, Header[] headers,
            byte[] responseBody, Throwable error) {
        tv_status.setText("http請求失敗"+new String(responseBody));
    }
 });
3、發送post請求
String path = "http://192.168.1.103:8080/web/LoginServlet";
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
params.put("qq", qq);
params.put("pwd", pwd);
client.post(path, params, new AsyncHttpResponseHandler(){
    @Override
    public void onSuccess(int statusCode, Header[] headers,
            byte[] responseBody) {
        tv_status.setText("登陸結果:"+new String(responseBody));
    }
    @Override
    public void onFailure(int statusCode, Header[] headers,
            byte[] responseBody, Throwable error) {
        tv_status.setText("請求失敗請檢查網絡");
    }
});
 

1.簡介

Android中網絡請求一般使用Apache HTTP Client或者采用HttpURLConnect,但是直接使用這兩個類庫需要寫大量的代碼才能完成網絡post和get請求,而使用android-async-http這個庫可以大大的簡化操作,它是基於Apache’s HttpClient ,所有的請求都是獨立在UI主線程之外,通過回調方法處理請求結果,采用android Handlermessage 機制傳遞信息。

2.特性
(1)采用異步http請求,並通過匿名內部類處理回調結果
(2)http請求獨立在UI主線程之外
(3)采用線程池來處理並發請求
(4)采用RequestParams類創建GET/POST參數
(5)不需要第三方包即可支持Multipart file文件上傳
(6)大小只有25kb
(7)自動為各種移動電話處理連接斷開時請求重連
(8)超快的自動gzip響應解碼支持
(9)使用BinaryHttpResponseHandler類下載二進制文件(如圖片)
(10) 使用JsonHttpResponseHandler類可以自動將響應結果解析為json格式
(11)持久化cookie存儲,可以將cookie保存到你的應用程序的SharedPreferences中

3.使用方法
(1)到官網http://loopj.com/android-async-http/下載最新的android-async-http-1.4.4.jar,然後將此jar包添加進Android應用程序 libs文件夾
(2)通過import com.loopj.android.http.*;引入相關類
(3)創建異步請求

[java]view plaincopy  
  1. AsyncHttpClientclient=newAsyncHttpClient();
  2. client.get("http://www.google.com",newAsyncHttpResponseHandler(){
  3. @Override
  4. publicvoidonSuccess(Stringresponse){
  5. System.out.println(response);
  6. }
  7. });
4.建議使用靜態的Http Client對象
在下面這個例子,我們創建了靜態的http client對象,使其很容易連接到Twitter的API
[java]view plaincopy
  1. importcom.loopj.android.http.*;
  2.  
  3. publicclassTwitterRestClient{
  4. privatestaticfinalStringBASE_URL="http://api.twitter.com/1/";
  5.  
  6. privatestaticAsyncHttpClientclient=newAsyncHttpClient();
  7.  
  8. publicstaticvoidget(Stringurl,RequestParamsparams,AsyncHttpResponseHandlerresponseHandler){
  9. client.get(getAbsoluteUrl(url),params,responseHandler);
  10. }
  11.  
  12. publicstaticvoidpost(Stringurl,RequestParamsparams,AsyncHttpResponseHandlerresponseHandler){
  13. client.post(getAbsoluteUrl(url),params,responseHandler);
  14. }
  15.  
  16. privatestaticStringgetAbsoluteUrl(StringrelativeUrl){
  17. returnBASE_URL+relativeUrl;
  18. }
  19. } 然後我們可以很容易的在代碼中操作Twitter的API
[java]view plaincopy
  1. importorg.json.*;
  2. importcom.loopj.android.http.*;
  3.  
  4. classTwitterRestClientUsage{
  5. publicvoidgetPublicTimeline()throwsJSONException{
  6. TwitterRestClient.get("statuses/public_timeline.json",null,newJsonHttpResponseHandler(){
  7. @Override
  8. publicvoidonSuccess(JSONArraytimeline){
  9. //Pulloutthefirsteventonthepublictimeline
  10. JSONObjectfirstEvent=timeline.get(0);
  11. StringtweetText=firstEvent.getString("text");
  12.  
  13. //Dosomethingwiththeresponse
  14. System.out.println(tweetText);
  15. }
  16. });
  17. }
  18. }
5. AsyncHttpClient, RequestParams ,AsyncHttpResponseHandler三個類使用方法
(1)AsyncHttpClient

public class AsyncHttpClient extends java.lang.Object
該類通常用在android應用程序中創建異步GET, POST, PUT和DELETE HTTP請求,請求參數通過RequestParams實例創建,響應通過重寫匿名內部類 ResponseHandlerInterface的方法處理。
例子:
[java]view plaincopy  
  1. AsyncHttpClientclient=newAsyncHttpClient();
  2. client.get("http://www.google.com",newResponseHandlerInterface(){
  3. @Override
  4. publicvoidonSuccess(Stringresponse){
  5. System.out.println(response);
  6. }
  7. });
(2)RequestParams
public class RequestParams extends java.lang.Object
用於創建AsyncHttpClient實例中的請求參數(包括字符串或者文件)的集合
例子:
[java]view plaincopy
  1. RequestParamsparams=newRequestParams();
  2. params.put("username","james");
  3. params.put("password","123456");
  4. params.put("email","[email protected]");
  5. params.put("profile_picture",newFile("pic.jpg"));//UploadaFile
  6. params.put("profile_picture2",someInputStream);//UploadanInputStream
  7. params.put("profile_picture3",newByteArrayInputStream(someBytes));//Uploadsomebytes
  8.  
  9. Mapmap=newHashMap();
  10. map.put("first_name","James");
  11. map.put("last_name","Smith");
  12. params.put("user",map);//urlparams:"user[first_name]=James&user[last_name]=Smith"
  13.  
  14. Setset=newHashSet();//unorderedcollection
  15. set.add("music");
  16. set.add("art");
  17. params.put("like",set);//urlparams:"like=music&like=art"
  18.  
  19. Listlist=newArrayList();//Orderedcollection
  20. list.add("Java");
  21. list.add("C");
  22. params.put("languages",list);//urlparams:"languages[]=Java&languages[]=C"
  23.  
  24. String[]colors={"blue","yellow"};//Orderedcollection
  25. params.put("colors",colors);//urlparams:"colors[]=blue&colors[]=yellow"
  26.  
  27. List>listOfMaps=newArrayList>();
  28. Mapuser1=newHashMap();
  29. user1.put("age","30");
  30. user1.put("gender","male");
  31. Mapuser2=newHashMap();
  32. user2.put("age","25");
  33. user2.put("gender","female");
  34. listOfMaps.add(user1);
  35. listOfMaps.add(user2);
  36. params.put("users",listOfMaps);//urlparams:"users[][age]=30&users[][gender]=male&users[][age]=25&users[][gender]=female"
  37.  
  38. AsyncHttpClientclient=newAsyncHttpClient();
  39. client.post("http://myendpoint.com",params,responseHandler); (3)public class AsyncHttpResponseHandler extends java.lang.Object implements ResponseHandlerInterface
    用於攔截和處理由AsyncHttpClient創建的請求。在匿名類AsyncHttpResponseHandler中的重寫 onSuccess(int, org.apache.http.Header[], byte[])方法用於處理響應成功的請求。此外,你也可以重寫 onFailure(int, org.apache.http.Header[], byte[], Throwable), onStart(), onFinish(), onRetry() 和onProgress(int, int)方法
    例子:
    [java]view plaincopy  
    1. AsyncHttpClientclient=newAsyncHttpClient();
    2. client.get("http://www.google.com",newAsyncHttpResponseHandler(){
    3. @Override
    4. publicvoidonStart(){
    5. //Initiatedtherequest
    6. }
    7.  
    8. @Override
    9. publicvoidonSuccess(intstatusCode,Header[]headers,byte[]responseBody){
    10. //Successfullygotaresponse
    11. }
    12.  
    13. @Override
    14. publicvoidonFailure(intstatusCode,Header[]headers,byte[]responseBody,Throwableerror)
    15. {
    16. //Responsefailed:(
    17. }
    18.  
    19. @Override
    20. publicvoidonRetry(){
    21. //Requestwasretried
    22. }
    23.  
    24. @Override
    25. publicvoidonProgress(intbytesWritten,inttotalSize){
    26. //Progressnotification
    27. }
    28.  
    29. @Override
    30. publicvoidonFinish(){
    31. //Completedtherequest(eithersuccessorfailure)
    32. }
    33. });
6.利用PersistentCookieStore持久化存儲cookie
PersistentCookieStore類用於實現Apache HttpClient的CookieStore接口,可以自動的將cookie保存到Android設備的SharedPreferences中,如果你打算使用cookie來管理驗證會話,這個非常有用,因為用戶可以保持登錄狀態,不管關閉還是重新打開你的app
(1)首先創建 AsyncHttpClient實例對象
[java]view plaincopy
  1. AsyncHttpClientmyClient=newAsyncHttpClient(); (2)將客戶端的cookie保存到PersistentCookieStore實例對象,帶有activity或者應用程序context的構造方法
    [java]view plaincopy  
  2. PersistentCookieStoremyCookieStore=newPersistentCookieStore(this);
  3. myClient.setCookieStore(myCookieStore); (3)任何從服務器端獲取的cookie都會持久化存儲到myCookieStore中,添加一個cookie到存儲中,只需要構造一個新的cookie對象,並且調用addCookie方法
    [java]view plaincopy  
    1. BasicClientCookienewCookie=newBasicClientCookie("cookiesare","awesome");
    2. newCookie.setVersion(1);
    3. newCookie.setDomain("mydomain.com");
    4. newCookie.setPath("/");
    5. myCookieStore.addCookie(newCookie);
7.利用RequestParams上傳文件
類RequestParams支持multipart file 文件上傳
(1)在RequestParams 對象中添加InputStream用於上傳
[java]view plaincopy
  1. InputStreammyInputStream=blah;
  2. RequestParamsparams=newRequestParams();
  3. params.put("secret_passwords",myInputStream,"passwords.txt"); (2)添加文件對象用於上傳
[java]view plaincopy
  1. FilemyFile=newFile("/path/to/file.png");
  2. RequestParamsparams=newRequestParams();
  3. try{
  4. params.put("profile_picture",myFile);
  5. }catch(FileNotFoundExceptione){} (3)添加字節數組用於上傳
[java]view plaincopy
  1. byte[]myByteArray=blah;
  2. RequestParamsparams=newRequestParams();
  3. params.put("soundtrack",newByteArrayInputStream(myByteArray),"she-wolf.mp3");
8.用BinaryHttpResponseHandler下載二進制數據 七、使用post請求上傳文件   使用異步網絡請求框架上傳文件時,只需要將請求的參數設置為要上傳的文件即可
public void upload(View view){
    String path = et_path.getText().toString().trim();
    File file = new File(path);
    if(file.exists()&&file.length()>0){
        //上傳
        AsyncHttpClient client = new AsyncHttpClient();
        RequestParams params = new RequestParams();
        try {
            params.put("file", file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        client.post("http://192.168.1.103:8080/web/UploadServlet", params, new AsyncHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
                Toast.makeText(MainActivity.this, "上傳成功", 0).show();
            }
            
            @Override
            public void onFailure(int statusCode, Header[] headers,
                    byte[] responseBody, Throwable error) {
                Toast.makeText(MainActivity.this, "上傳失敗", 0).show();
            }
        });
        
    }else{
        Toast.makeText(this, "請檢查文件是否存在", 0).show();
    }
}  
   
八、使用HttpUtils加載網絡 1、發送get請求
HttpUtils http = new HttpUtils();
        http.send(HttpRequest.HttpMethod.GET,
            "http://www.lidroid.com",
            new RequestCallBack(){
                @Override
                public void onLoading(long total, long current, boolean isUploading) {
                    testTextView.setText(current + "/" + total);
                }
                @Override
                public void onSuccess(ResponseInfo responseInfo) {
                    textView.setText(responseInfo.result);
                }
                @Override
                public void onStart() {
                }
                @Override
                public void onFailure(HttpException error, String msg) {
                }
        });
  2、下載 支持斷點續傳,隨時停止下載任務,開始任務  
 HttpUtils http = new HttpUtils();
    HttpHandler handler = http.download("http://apache.dataguru.cn/httpcomponents/httpclient/source/httpcomponents-client-4.2.5-src.zip",
        "/sdcard/httpcomponents-client-4.2.5-src.zip",
        true, // 如果目標文件存在,接著未完成的部分繼續下載。服務器不支持RANGE時將從新下載。
        true, // 如果從請求返回信息中獲取到文件名,下載完成後自動重命名。
        new RequestCallBack() {
            @Override
            public void onStart() {
                testTextView.setText("conn...");
            }
            @Override
            public void onLoading(long total, long current, boolean isUploading) {
                testTextView.setText(current + "/" + total);
            }
            @Override
            public void onSuccess(ResponseInfo responseInfo) {
                testTextView.setText("downloaded:" + responseInfo.result.getPath());
            }
            @Override
            public void onFailure(HttpException error, String msg) {
                testTextView.setText(msg);
            }
    });
         
  九、多線程下載 1、多線程下載的步驟 (1)在磁盤上創建一個與網絡文件相同大小的空白文件 (2)將文件劃分為若干塊,開啟多線程,下載文件,每個線程分別下載不同的塊 (3)當所有的線程都將自己的塊下載完成後,文件下載完成   2、具體實現步驟 (1)連接網絡,使用getContentLength()方法獲取網絡文件的大小 (2)使用RandomAccessFile在本地創建一個與網絡文件相同大小的空文件 (3)設置開啟多少個線程來下載 (4)為每個線程設置需要下載的文件大小(每個線程下載的大小=總文件大小/線程數),設置每個線程下載的區域由於不不能被整除,所以最後一個線程多下載一點,特殊處理 (5)創建線程下載文件 (6)線程連接網絡 (7)高告訴服務器只需要下載一部分內容conn.setRequestProperty("Range","bytes="+currentPosition+"-"+endIndex);
Range表示范圍,後面的字符串為范圍值
(8)使用隨機文件訪問流的seek(intindex)方法設置每個線程下載文件後在本地文件中寫入的起始位置
(9)將獲取到的數據寫入到本地文件中
 
public void download(View view) {
    path = et_path.getText().toString().trim();
    if (TextUtils.isEmpty(path) || (!path.startsWith("http://"))) {
        Toast.makeText(this, "對不起路徑不合法", 0).show();
        return;
    }
    new Thread(){
        public void run() {
            try {
                //1、連接網絡
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(5000);
                conn.setRequestMethod("GET");
                int code = conn.getResponseCode();
                if (code == 200) {
                    //2、使用getContentLength()方法獲取網絡文件的大小
                    int length = conn.getContentLength();
                    System.out.println("服務器文件的長度為:" + length);
                    //3、使用RandomAccessFile在本地創建一個空文件
                    RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+getFileName(path), "rw");
                    //4、將空文件的大小設置為與網絡文件大小相同
                    raf.setLength(length);
                    raf.close();
                    //5、設置將文件劃分的塊數,threadCount--線程數
                    int blocksize = length / threadCount;
                    runningThreadCount = threadCount;
                    //6、設置每個線程下載的文件區域
                    for (int threadId = 0; threadId < threadCount; threadId++) {
                        int startIndex = threadId * blocksize;
                        int endIndex = (threadId + 1) * blocksize - 1;
                        if (threadId == (threadCount - 1)) {
                            endIndex = length - 1;
                        }
                        new DownloadThread(threadId, startIndex, endIndex).start();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        };
    }.start();
}
//創建線程下載文件
private class DownloadThread extends Thread {
    /**
     * 線程id
     */
    private int threadId;
    /**
     * 線程下載的理論開始位置
     */
    private int startIndex;
    /**
     * 線程下載的結束位置
     */
    private int endIndex;
    /**
     * 當前線程下載到文件的那一個位置了.
     */
    private int currentPosition;
    public DownloadThread(int threadId, int startIndex, int endIndex) {
        this.threadId = threadId;
        this.startIndex = startIndex;
        this.endIndex = endIndex;
        System.out.println(threadId + "號線程下載的范圍為:" + startIndex
                + "   ~~   " + endIndex);
        currentPosition = startIndex;
    }
    @Override
    public void run() {
        try {
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            //檢查當前線程是否已經下載過一部分的數據了 
            File info = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+threadId+".position");
            RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+getFileName(path), "rw");
            if(info.exists()&&info.length()>0){
                FileInputStream fis = new FileInputStream(info);
                BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                currentPosition = Integer.valueOf(br.readLine());
                conn.setRequestProperty("Range", "bytes="+currentPosition+"-"+endIndex);
                System.out.println("原來有下載進度,從上一次終止的位置繼續下載"+"bytes="+currentPosition+"-"+endIndex);
                fis.close();
                raf.seek(currentPosition);//每個線程寫文件的開始位置都是不一樣的.
            }else{
            //告訴服務器 只想下載資源的一部分
                conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
                System.out.println("原來沒有有下載進度,新的下載"+ "bytes="+startIndex+"-"+endIndex);
                raf.seek(startIndex);//每個線程寫文件的開始位置都是不一樣的.
            }
            InputStream is = conn.getInputStream();
            byte[] buffer = new byte[1024];
            int len = -1;
            while((len = is.read(buffer))!=-1){
                //把每個線程下載的數據放在自己的空間裡面.
//                System.out.println("線程:"+threadId+"正在下載:"+new String(buffer));
                raf.write(buffer,0, len);
                currentPosition+=len;
                File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+threadId+".position");
                RandomAccessFile fos = new RandomAccessFile(file,"rwd");
                //System.out.println("線程:"+threadId+"寫到了"+currentPosition);
                fos.write(String.valueOf(currentPosition).getBytes());
                fos.close();//fileoutstream數據是不一定被寫入到底層設備裡面的,有可能是存儲在緩存裡面.
                //raf 的 rwd模式,數據是立刻被存儲到底層硬盤設備裡面.
                int max = endIndex - startIndex;
                int progress = currentPosition - startIndex;
                if(threadId==0){
                    pb0.setMax(max);
                    pb0.setProgress(progress);
                }else if(threadId==1){
                    pb1.setMax(max);
                    pb1.setProgress(progress);
                }else if(threadId==2){
                    pb2.setMax(max);
                    pb2.setProgress(progress);
                }
            }
            raf.close();
            is.close();
            System.out.println("線程:"+threadId+"下載完畢了...");
            File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+threadId+".position");
            f.renameTo(new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+threadId+".position.finish"));
            synchronized (MainActivity.class) {
                runningThreadCount--;
                if(runningThreadCount<=0){
                    for(int i=0;i
/**
 * 獲取一個文件名稱
 * @param path
 * @return
 */
public String getFileName(String path){
    int start = path.lastIndexOf("/")+1;
    return path.substring(start);
}  



  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved