AsyncTask解析(下)——實現自定義AsyncTask網路傳輸工具類封裝
在上文: AsyncTask解析(上)——原理分析與超簡單demo實現中已經對AsyncTask的實現原理以及原始碼流程進行了一定的分析,相信大家已經基本熟悉了AsyncTask內部實現網路傳輸的呼叫順序以及過程細節,最後還寫出了一個比較簡單的Demo實踐,十分簡單易懂相信大家都能很快掌握。
然而那個Demo還是太粗製濫造了,功能太缺乏,很多需要傳入的引數也沒有寫到構參裡直接給寫死了..
並且在真正的專案實踐中,光使用這個簡單的Demo是遠遠不夠的,我們需要對它進行更好的封裝,擴充套件它的功能,才能更好地為我們的專案服務。
所以,本文的核心重點是如何去封裝出一個AsyncTask工具類,以及如何讓
整體框架的繼承關係如下圖所示:
理清一下思路,整體框架應用觀察者模式,可以細分為以下幾個步驟:
1、實現一個抽象類UrlAsyNet繼承AsyncTask<String,Integer,T>(這裡第三個引數設定為T是為了適配不同的傳輸型別)。
這裡為什麼不用介面呢?因為介面的方法是不能有具體的實現的,但是在該方法中需要進行初始化的工作,所以這裡使用了抽象類來實現。
/** * Created by nangua on 2016/4/26. * Params 啟動任務執行的輸入引數,這裡是URL所以用String * Progress 後臺任務執行的百分比。 * Result 後臺執行任務最終返回的結果,比如String。 */ public class UrlAsyNet<T> extends AsyncTask<String,Integer,T> { /** * 全部引數構造方法 * @param apikey * @param httpArg * @param httpUrl * @param method * @param onNetStateChangedListener * @param type */ public UrlAsyNet(String apikey, String httpArg, String httpUrl, NetMethod method, OnNetStateChangedListener<T> onNetStateChangedListener, ParamType type) { this.apikey = apikey; this.httpArg = httpArg; this.httpUrl = httpUrl; this.method = method; this.onNetStateChangedListener = onNetStateChangedListener; this.type = type; } /** * 傳入URL * @param httpUrl */ public UrlAsyNet(String httpUrl,String apikey,String httpArg) { this.httpUrl = httpUrl; this.apikey = apikey; this.httpArg = httpArg; } //新增列舉型別 public enum NetMethod{ GET,POST } /** * 引數型別。分為:JSONorXML檔案。鍵值對,無參 */ public enum ParamType{ JSON_OR_XML_FILE ,KEY_VALUE_PAIR, NO_PARAM } /** * 網路狀態改變時候的監聽器 * @param <T> */ public interface OnNetStateChangedListener<T> { /** * 訪問網路之前 */ public void beforeAccessNet(); /** * 訪問網路成功獲取資料之後 * * @param result */ public void afterAccessNet(T result); /** * 出現了錯誤的時候 */ public void whenException(); /** * 執行進度 * @param progress */ public void onProgress(Integer progress); } //設定監聽器回撥 public OnNetStateChangedListener<T> getOnNetStateChangedListener() { return onNetStateChangedListener; } //設定網路監聽器 public void setOnNetStateChangedListener(OnNetStateChangedListener<T> onNetStateChangedListener) { this.onNetStateChangedListener = onNetStateChangedListener; } //網路監聽器例項 OnNetStateChangedListener<T> onNetStateChangedListener; //在四個回撥方法中呼叫網路監聽器的方法以實現回撥 @Override protected void onCancelled() { if (onNetStateChangedListener!=null){ onNetStateChangedListener.whenException(); } } @Override protected void onPostExecute(T t) { if (onNetStateChangedListener!=null){ onNetStateChangedListener.afterAccessNet(t); } } @Override protected void onPreExecute() { if (onNetStateChangedListener!=null){ onNetStateChangedListener.beforeAccessNet(); } } @Override protected void onProgressUpdate(Integer... values) { if (onNetStateChangedListener!=null){ if (values.length>1) { onNetStateChangedListener.onProgress(values[0]); } } } //使用HttpURLConnection需要用到的httpUrl String httpUrl ; //使用HttpURLConnection需要用到的httpArg String httpArg ; //連線百度API需要的APIKEY String apikey; //得到的引數型別 ParamType type; //網路請求引數(GET或POST) NetMethod method; //資料 String jsonOrXmlFile; //鍵值對 HashMap<String, Object> keyValuePair; public String getHttpUrl() { return httpUrl; } public void setHttpUrl(String httpUrl) { this.httpUrl = httpUrl; } public String getApikey() { return apikey; } public void setApikey(String apikey) { this.apikey = apikey; } public String getHttpArg() { return httpArg; } public void setHttpArg(String httpArg) { this.httpArg = httpArg; } public ParamType getType() { return type; } public void setType(ParamType type) { this.type = type; } @Override protected T doInBackground(String... params) { return null; } /** * 執行 */ public void execute(){ this.execute(new String[]{}); } }
2、在抽象類裡編寫一個網路監聽器介面。然後在需要使用到的地方(比如在MainActivity裡需要使用,就在MainActivity裡寫一個實現這個介面的內部類,從而在這個內部類裡實現隨著網路狀態的改變改變對UI的操作)。
那麼問題來了:這裡為什麼不把元件當做引數傳進去呢?比如在上文中的Demo是把TextView和ProgressBar傳進去的,那麼如果你要傳入的是一個CustView呢?這樣就得重新修改寫好的程式碼,拆輪子,違背了程式的可擴充套件性。所以更好的辦法是提供一個可實現的網路監聽介面,在接口裡進行更新UI操作。
網路監聽器的程式碼上文已經出現了,這裡單獨列出來一下。/** * 網路狀態改變時候的監聽器 * @param <T> */ public interface OnNetStateChangedListener<T> { /** * 訪問網路之前 */ public void beforeAccessNet(); /** * 訪問網路成功獲取資料之後 * * @param result */ public void afterAccessNet(T result); /** * 出現了錯誤的時候 */ public void whenException(); /** * 執行進度 * @param progress */ public void onProgress(Integer progress); }
3、編寫具體的工具類UrlNormalAsyNet,實現對資料的接受(暫時沒有寫JSON和XML的解析):
/**
* Created by nangua on 2016/4/26.
*/
public class UrlNormalAsyNet extends UrlAsyNet<String>{
/**
* 請求方法POST和get
*/
AsyNet.NetMethod method;
public UrlNormalAsyNet(String apikey, String httpArg, String httpUrl, NetMethod method, OnNetStateChangedListener<String> onNetStateChangedListener, ParamType type) {
super(apikey, httpArg, httpUrl, method, onNetStateChangedListener, type);
}
public UrlNormalAsyNet(String httpUrl, String apikey, String httpArg) {
super(httpUrl, apikey, httpArg);
this.httpUrl = httpUrl;
this.apikey = apikey;
this.httpArg = httpArg;
}
@Override
protected String doInBackground(String... params) {
BufferedReader reader = null;
String result = null;
StringBuffer sbf = new StringBuffer();
httpUrl = httpUrl + "?" + httpArg;
try {
URL url = new URL(httpUrl);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("apikey", apikey);
connection.connect();
InputStream is = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String strRead = null;
while ((strRead = reader.readLine()) != null) {
sbf.append(strRead);
sbf.append("\r\n");
}
reader.close();
result = sbf.toString();
if (result != null) {
publishProgress(100);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
執行截圖:
本文暫時更新到這裡,以後有時間再繼續更新
目標要實現的工具類有三個:UrlFileAsyNet(處理檔案網路傳輸資訊),UrlImageAsyNet(處理圖片傳輸資訊),UrlNormalAsyNet(處理JSON,XML,或String格式網路傳輸資訊)。
以下是大神同學Dikaros寫的完整AsyncTask工具包下載地址:https://github.com/Dikaros/AsyNet
QAQ(づ ̄ 3 ̄)づ求贊求關注!