Android : 自己寫個HTTP框架


1.this libaray is base on AsyncTask ,AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

2.I encapsulate http request params into Request . you can access the cloud like this:

final Request request = new Request(url);// link url , the default constructor is GET request

request.addHeader("accept", "application/json");    // set request headers

request.addPostParams(key, value); // set post content

request.setRequestListener(new IRequestListener() {// when the AsyncTask execute , it will callback let code to handle something

@Override

public void onProgressUpdate(int status, int curPos, int totalPos) {// callback to update UI progress

@Override

public void onPreExecute() {    // callback , this is in UI thread , you may show progress or do sth prepare

}

@Override

public void onPostExecute() {   // callback , this is in UI thread , you may show the tips that http has done

}

@Override

public void onPrepareParams(OutputStream out) { // callback , you can use OutputStream to push the post content yourself

}

@Override

public void onCancelled() {    // callback , this is in UI thread , you may show that the http connection has been cancelled

}

@Override

public void onBeforeDoingBackground() {  // callback , this is in Sub thread , you may do sth preparation , like query db , prepare the post params.

}

@Override

public Object onAfterDoingBackground(Object object) {  // callback , this is in Sub thread, you may do sth that insert/update db , create files .etc

return null;

}

});

request.setCallback(new JsonCallback<Companies>() {// callback , this is in UI thread , will return the data that http response.

@Override

public void onCallback(Companies callback) {// the callback can be DTOs , path that write data into file , or just String data

for (Company company : callback.companies) {

Trace.d(company.toString());

}

assertTrue(callback.companies.size() > 0);

}

@Override

public void onFailure(Exception e) {// e can be CloudException , AbortException or other RuntimeException

throw new AssertionError(e.toString());

}

}.setReturnType(Companies.class)

.setFilePath(path) // if you want save the data into file first , you can setFilePath(path).

);// setReturnType , if you want callback to return you the exactly DTO , pls set the Class and use JsonCallback , it will deserialize automatically , and return object to you

request.execute();// execute the code to http access. if you just for test ,pls call request.test()  . this method is only for test .

 

首先分析下需求。

在Android里,我們常常要通過網絡去獲取數據,然后更新UI,網絡請求當然要放到子線程里,然后更新UI在主線程,所以基於這樣的需求,Android才提供了AsyncTask,所以我們再基於AsyncTask再做一次封裝,這樣,網絡請求就變的方便的多。你再也不用煩躁於線程切換,重復寫代碼了。一個好車輪能讓你省很多時間。

首先定義一個Request類,把所有可能用到的參數define在里面,比如callback(服務器返回的數據),params(push到服務器的data),listener(下載進度,執行過程)。。。

網絡請求有Get Post。。為了低耦合,基本都要拆開,比如我會用HttpClient 也可能用HttpUrlConnection.那么寫個HttpUtil用來封裝http的請求代碼。這里定義一個execute()方法,在這個方法里判斷是get還是post請求,再去call get() post() 方法,那么post請求需要push data到服務器,所以你要把params設置到Request中,有可能你需要push file到服務器,所以我添加了一個回調方法,把OutputStream傳回去,手動的把file flush到Stream中。

在AsyncTask中,在doingBackground()方法中execute http,然后再調用AbstractCallback預先處理服務器返回的InputStream,如果data不大,可以直接寫到內存變成String返回,如果data比較大,建議寫到tmp文件里,把path返回,在不同的callback里再處理。所以就會有不同的callback,StringCallback PathCallback JsonCallback 你也可以根據你的特殊需求來定義不同的callback,你也可以在callback里將數據deserialize到database中。這樣創建一個網絡請求代碼就會非常輕松。

貼個AbstractCallback處理流的方法,因為我沒裝代碼插件,大家先湊合看,改天我加上了就會好很多了。

public Object handleConnection(HttpURLConnection response,

IProgressListener task) throws Exception {

try {

checkIsCancelled();

int statusCode = response.getResponseCode();

long contentLength = response.getContentLength();

InputStream in = null;

if (statusCode == HttpStatus.SC_OK) {

String encoding = response.getContentEncoding();

if (encoding != null && "gzip".equals(encoding))

in = new GZIPInputStream(response.getInputStream());

else if (encoding != null && "deflate".equals(encoding))

in = new InflaterInputStream(response.getInputStream());

else

in = response.getInputStream();

// if set path , write the data into file

if (!TextUtils.isEmpty(path)) {

FileOutputStream fos = new FileOutputStream(path);

byte[] b = new byte[IO_BUFFER_SIZE];

int curPos = 0;

int read;

while ((read = in.read(b)) != -1) {

checkIsCancelled();

if (task != null) {

curPos += read;

task.onProgressUpdate(

IProgressListener.DOWNLOADING,

curPos / 1000, contentLength == -1 ? -1

: (int) (contentLength / 1000));

}

fos.write(b, 0, read);

}

fos.flush();

fos.close();

in.close();

return bindData(path, task);

} else {

return bindData(

new String(IOUtilities.readStreamToMemory(in)), task);

}

} else {

throw new CloudException(statusCode,

response.getResponseMessage(), new String(

IOUtilities.readStreamToMemory(response

.getErrorStream())));

}

} finally {

if (response != null) {

response.disconnect();

response = null;

}

}

}

寫框架,你必須要考慮全面,想所有不同的可能性,但是要有個度,全部想要封裝也是很難的,所以基於不同的項目,框架也會發生改變。大家也不要迷信於某個框架能滿足你所有的需求。你應該造你需要的輪子,能跑的最快的輪子。

源代碼改天再提供。大家可以先自己考慮考慮,搭框架不難,主要是要有個全局觀。也就是代碼寫的多了,煩了,想偷懶了,框架雛形就出來了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM