Android開發之使用HTTP訪問網絡資源
來源:程序員人生 發布時間:2014-10-19 08:00:01 閱讀次數:3147次
使用HTTP訪問網絡資源
前面介紹了 URLConnection己經可以非常方便地與指定站點交換信息,URLConnection還有一個子類:HttpURLConnection,HttpURLConnection 在 LIRLConnection的基礎上做了進一步改進,增加了一些用于操作http資源的便捷方法。
1.使用HttpURLConnection
HttpURLConnection繼承了URLConnection,因此也可用于向指定網站發送GET請求 POST請求。它在URLConnection的基礎上提供了如下便捷的方法。
1)
Int getResponseCode():獲取服務器的響應代碼。
2)
String getResponseMessage():獲取服務器的響應消息。
3)
String getRequestMethod():獲取發送請求的方法。
4)
void setRequestMethod(String method):設置發送請求的方法。
下面通過個實用的示例來示范使用HttpURLConnection實現多線程下載。
1.1實例:多線程下載
使用多線程下載文件可以更快地完成文件的下載,因為客戶端啟動多個線程進行下寒意味著服務器也需要為該客戶端提供相應的服務。假設服務器同時最多服務100個用戶,服務器中一條線程對應一個用戶,100條線程在計算機內并發執行,也就是由CPU劃分史 片輪流執行,如果A應用使用了 99條線程下載文件,那么相當于占用了 99個用戶的資源自然就擁有了較快的下載速度。
提示:實際上并不是客戶端并發的下載線程越多,程序的下載速度就越快,因為當客戶端開啟太多的并發線程之后,應用程序需要維護每條線程的開銷、線程同步的開銷,這些開銷反而會導致下載速度降低.
1.2為了實現多線程下載,程序可按如下步驟進行:
?
創建URL對象。
?
獲取指定URL對象所指向資源的大小(由getContentLength()方法實現),此處用了 HttpURLConnection 類。
?
在本地磁盤上創建一個與網絡資源相同大小的空文件。
?
計算每條線程應該下載網絡資源的哪個部分(從哪個字節開始,到哪個字節結束,依次創建、啟動多條線程來下載網絡資源的指定部分。
1.2該程序提供的下載工具類代碼如下。
package com.jph.net;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* Description:
* 創建ServerSocket監聽的主類
* @author jph
* Date:2014.08.27
*/
public class DownUtil
{
/**下載資源的路徑**/
private String path;
/**下載的文件的保存位置**/
private String targetFile;
/**需要使用多少線程下載資源**/
private int threadNum;
/**下載的線程對象**/
private DownThread[] threads;
/**下載的文件的總大小**/
private int fileSize;
public DownUtil(String path, String targetFile, int threadNum)
{
this.path = path;
this.threadNum = threadNum;
// 初始化threads數組
threads = new DownThread[threadNum];
this.targetFile = targetFile;
}
public void download() throws Exception
{
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5 * 1000);
conn.setRequestMethod("GET");
conn.setRequestProperty(
"Accept",
"image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
+ "application/x-shockwave-flash, application/xaml+xml, "
+ "application/vnd.ms-xpsdocument, application/x-ms-xbap, "
+ "application/x-ms-application, application/vnd.ms-excel, "
+ "application/vnd.ms-powerpoint, application/msword, */*");
conn.setRequestProperty("Accept-Language", "zh-CN");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Connection", "Keep-Alive");
// 得到文件大小
fileSize = conn.getContentLength();
conn.disconnect();
int currentPartSize = fileSize / threadNum + 1;
RandomAccessFile file = new RandomAccessFile(targetFile, "rw");
// 設置本地文件的大小
file.setLength(fileSize);
file.close();
for (int i = 0; i < threadNum; i++)
{
// 計算每條線程的下載的開始位置
int startPos = i * currentPartSize;
// 每個線程使用一個RandomAccessFile進行下載
RandomAccessFile currentPart = new RandomAccessFile(targetFile,
"rw");
// 定位該線程的下載位置
currentPart.seek(startPos);
// 創建下載線程
threads[i] = new DownThread(startPos, currentPartSize,
currentPart);
// 啟動下載線程
threads[i].start();
}
}
// 獲取下載的完成百分比
public double getCompleteRate()
{
// 統計多條線程已經下載的總大小
int sumSize = 0;
for (int i = 0; i < threadNum; i++)
{
sumSize += threads[i].length;
}
// 返回已經完成的百分比
return sumSize * 1.0 / fileSize;
}
private class DownThread extends Thread
{
/**當前線程的下載位置**/
private int startPos;
/**定義當前線程負責下載的文件大小**/
private int currentPartSize;
/**當前線程需要下載的文件塊**/
private RandomAccessFile currentPart;
/**定義該線程已下載的字節數**/
public int length;
public DownThread(int startPos, int currentPartSize,
RandomAccessFile currentPart)
{
this.startPos = startPos;
this.currentPartSize = currentPartSize;
this.currentPart = currentPart;
}
@Override
public void run()
{
try
{
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection)url
.openConnection();
conn.setConnectTimeout(5 * 1000);
conn.setRequestMethod("GET");
conn.setRequestProperty(
"Accept",
"image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
+ "application/x-shockwave-flash, application/xaml+xml, "
+ "application/vnd.ms-xpsdocument, application/x-ms-xbap, "
+ "application/x-ms-application, application/vnd.ms-excel, "
+ "application/vnd.ms-powerpoint, application/msword, */*");
conn.setRequestProperty("Accept-Language", "zh-CN");
conn.setRequestProperty("Charset", "UTF-8");
InputStream inStream = conn.getInputStream();
// 跳過startPos個字節,表明該線程只下載自己負責哪部分文件。
inStream.skip(this.startPos);
byte[] buffer = new byte[1024];
int hasRead = 0;
// 讀取網絡數據,并寫入本地文件
while (length < currentPartSize
&& (hasRead = inStream.read(buffer)) > 0)
{
currentPart.write(buffer, 0, hasRead);
// 累計該線程下載的總大小
length += hasRead;
}
currentPart.close();
inStream.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
上而的DownUtil工具類中包括一個DownloadThread內部類,該內部類的run()方法中負責打開遠程資源的輸入流,并調用inputStream的skip(int)方法跳過指定數量的字節,這樣就讓該線程讀取由它自己負責下載的部分。
提供了上面的DownUtil工具類之后,接下來就可以在Activity中調用該DownUtil類來執行下載任務,該程序界面中包含兩個文本框,一個用于輸入網絡文件的源路徑,另一個用于指定下載到本地的文件的文件名,該程序的界面比較簡單,故此處不再給出界面布局代碼。該程序的Activity代碼如下。
package com.jph.net;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
/**
* Description:
* 多線程下載
* @author jph
* Date:2014.08.27
*/
public class MultiThreadDown extends Activity
{
EditText url;
EditText target;
Button downBn;
ProgressBar bar;
DownUtil downUtil;
private int mDownStatus;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 獲取程序界面中的三個界面控件
url = (EditText) findViewById(R.id.url);
target = (EditText) findViewById(R.id.target);
downBn = (Button) findViewById(R.id.down);
bar = (ProgressBar) findViewById(R.id.bar);
// 創建一個Handler對象
final Handler handler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
if (msg.what == 0x123)
{
bar.setProgress(mDownStatus);
}
}
};
downBn.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
// 初始化DownUtil對象(最后一個參數指定線程數)
downUtil = new DownUtil(url.getText().toString(),
target.getText().toString(), 6);
new Thread()
{
@Override
public void run()
{
try
{
// 開始下載
downUtil.download();
}
catch (Exception e)
{
e.printStackTrace();
}
// 定義每秒調度獲取一次系統的完成進度
final Timer timer = new Timer();
timer.schedule(new TimerTask()
{
@Override
public void run()
{
// 獲取下載任務的完成比率
double completeRate = downUtil.getCompleteRate();
mDownStatus = (int) (completeRate * 100);
// 發送消息通知界面更新進度條
handler.sendEmptyMessage(0x123);
// 下載完全后取消任務調度
if (mDownStatus >= 100)
{
showToastByRunnable(MultiThreadDown.this, "下載完成", 2000);
timer.cancel();
}
}
}, 0, 100);
}
}.start();
}
});
}
/**
* 在非UI線程中使用Toast
* @param context 上下文
* @param text 用以顯示的消息內容
* @param duration 消息顯示的時間
* */
private void showToastByRunnable(final Context context, final CharSequence text, final int duration) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, text, duration).show();
}
});
}
}
上面的Activity不僅使用了 DownUtil來控制程序下載,而且程序還啟動了一個定時器,該定時器控制每隔0.1秒
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈