Android網路框架初步嘗試
阿新 • • 發佈:2018-11-12
最近面試了很多公司,感慨良多,面試官都強調要多寫技術文章,多閱讀原始碼。仔細想想確實如此,想成為一名好的Android工程師,如果沒有原始碼閱讀,怎麼能寫出好的程式碼那。 因為是第一篇文章,肯定想拿出一點好東西帶大家分享。想想看自己也就寫過一個網路框架可以拿出來談談。 首先介紹我這個網路框架的思路 1.所有的網路請求都抽象成一個task. 2.網路請求可以配置執行的方式,比如在當前執行緒執行,在單執行緒池排隊執行,多執行緒池併發執行 3.網路請求的方法可以方便配置 4.網路解析的方式可以方便配置,比如公司是採用XML JSON 還是其他格式都要可以支援變更 以下是自己寫的https://github.com/OneOfBillions/NetExcutor 歡迎牛人來評鑑 這裡給大家預覽一些程式碼
這是一個執行請求的方法,可以看出使用builder模式可以有很多可以自由設定的
public static <T> Canceller executorCommonRequest(final Context context,
final NetUIListener<T> uiListener, final NetOptions
options) {
Canceller canceller = new Canceller(null);
try {
if (uiListener != null) {
OkHttpNetEngine engine = new OkHttpNetEngine(context);//網路引擎
NetRequestConfig.Builder builder = new NetRequestConfig.Builder();//設定請求引數
builder.setContext(context);
builder.setNetUIListener(uiListener);
builder.setOptions(options);
builder.setNetEngine(engine);
builder.setMethod(uiListener.getMethod());
builder.setDataParser(new JsonDataParser());
canceller = new Canceller(engine);
new CommonNetTask(builder.build()).start();
}
} catch (Exception e) {
Log.d(NetUtils.TAG, "網路請求錯誤: " + e.toString());
}
return canceller;
}
網路請求就是一個TASK
public abstract class NetTask implements Runnable {
/**
* 任務處理中的資料中轉.
*/
private HashMap<String, Object> data = new HashMap<>();
/**
* 單執行緒任務池.
*/
private static ExecutorService executorService = Executors
.newSingleThreadExecutor();
/**
* 多執行緒任務池.
*/
private static ExecutorService executorMutipleService = Executors
.newCachedThreadPool();
/**
* 單執行緒池,適用於時序要求的任務佇列.
*
* @param runnable the runnable
*/
public static void executeRunnbale(Runnable runnable) {
if (runnable != null) {
executorService.execute(runnable);
}
}
/**
* 網路請求的配置類.
*/
private NetRequestConfig netRequest;
/**
* Parameter.
*/
private NetParameter parameter;
/**
* Instantiates a new Net task.
*
* @param netRequest the net request
*/
public NetTask(NetRequestConfig netRequest) {
this.netRequest = netRequest;
if (netRequest != null) {
if (netRequest.getNetEngine() != null) {
if (netRequest.getOptions() != null) {
if (netRequest.getNetUIListener() != null) {
prepareCreateParameter();
this.parameter = netRequest.getNetUIListener().createNetParams();
if (this.parameter != null) {
//init success
} else {
throw new NetException("parameter 不能為空");
}
} else {
throw new NetException("uiListener 不能為空");
}
} else {
throw new NetException("option 不能為空");
}
} else {
throw new NetException("請設定一種執行網路任務的引擎");
}
} else {
throw new NetException("NetRequest 不能為空");
}
}
/**
* Prepare create parameter.
*/
public void prepareCreateParameter() {
}
/**
* Use cache refresh ui.
*
* @param <T> the type parameter
* @param localValue the local value
*/
public <T> void callback(String localValue) {
if (!TextUtils.isEmpty(localValue)) {
// 得到快取資料
T localResponseBean = GsonUtil.fromJsonStringToCollection(
localValue, getNetUiListener().getType());
if (localResponseBean != null) {
// 用快取資料先重新整理介面
callback(
NetUtils.NetRequestStatus.SUCCESS, localResponseBean);
}
}
}
/**
* 網路請求回撥
*
* @param <T> the type parameter
* @param netRequestStatus the net request status
* @param bean the bean
*/
public <T> void callback(
final NetUtils.NetRequestStatus netRequestStatus, final T bean) {
if (getNetUiListener() != null) {
if (getOptions().isPostUIThread()) {
//回撥到UI執行緒
if (getContext() != null && getContext() instanceof Activity) {
Activity activity = (Activity) getContext();
if (!activity.isFinishing()) {
boolean isDes = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
isDes = activity.isDestroyed();
}
if (!isDes) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
getNetUiListener().onComplete(bean, netRequestStatus);
}
});
}
}
}
} else {
//在任務執行執行緒執行回撥
getNetUiListener().onComplete(bean, netRequestStatus);
}
}
}
/**
* 多執行緒池,適用於並行任務的執行.
*
* @param runnable the runnable
*/
public static void executeMutipleRunnbale(Runnable runnable) {
if (runnable != null) {
executorMutipleService.execute(runnable);
}
}
/**
* Put handler info.
*
* @param key the key
* @param value the value
*/
public void putHandlerInfo(String key, Object value) {
if (!TextUtils.isEmpty(key)) {
data.put(key, value);
}
}
/**
* Gets handler info.
*
* @param <T> the type parameter
* @param key the key
* @param classOfT the class of t
* @return the handler info
*/
public <T> T getHandlerInfo(String key, Class<T> classOfT) {
if (!TextUtils.isEmpty(key) && classOfT != null) {
Object object = data.get(key);
if (object != null && classOfT.isInstance(object)) {
return (T) object;
}
}
return null;
}
/**
* Start.
*/
public void start() {
NetOptions netOptions = getOptions();
if (netOptions != null) {
switch (netOptions.getRunMode()) {
case SINGLE_THREAD_POOL:
executeRunnbale(this);
break;
case MUTIPLE_THREAD_POOL:
executeMutipleRunnbale(this);
break;
case CURRENT_THREAD:
this.run();
break;
}
}
}
/**
* Gets options.
*
* @return the options
*/
public NetOptions getOptions() {
return netRequest.getOptions();
}
/**
* Gets net engine.
*
* @return the net engine
*/
public NetEngine getNetEngine() {
return netRequest.getNetEngine();
}
/**
* Gets context.
*
* @return the context
*/
public Context getContext() {
return netRequest.getContext();
}
/**
* Gets net request.
*
* @return the net request
*/
public NetRequestConfig getNetRequest() {
return netRequest;
}
/**
* Gets net ui listener.
*
* @return the net ui listener
*/
public NetUIListener getNetUiListener() {
return netRequest.getNetUIListener();
}
/**
* Gets parameter.
*
* @return the parameter
*/
public NetParameter getParameter() {
return parameter;
}
/**
* Gets net data parser.
*
* @return the net data parser
*/
public NetDataParser getNetDataParser() {
return netRequest.getDataParser();
}
}
去實現一個通用的網路任務
public class CommonNetTask extends NetTask {
/**
* Instantiates a new Common net task.
*
* @param netRequest the net request
*/
public CommonNetTask(NetRequestConfig netRequest) {
super(netRequest);
}
/**
* Run.
*/
@Override
public void run() {
Object responseBean = null;
NetUtils.NetRequestStatus netRequestStatus = NetUtils.NetRequestStatus.SERVER_ERROR;
NetEngine engine = getNetEngine();
NetRequestConfig netRequest = getNetRequest();
NetResponseInfo netResponseInfo;
NetRequestConfig.Method method = netRequest.getMethod();
netResponseInfo = engine.request
(getParameter(),netRequest.getMethod());
String resultStr = null;
NetUIListener netUIListener = getNetUiListener();
Type type = netUIListener.getType();
if (netResponseInfo != null && netResponseInfo.isSuccess()) {
resultStr = netResponseInfo.getResult();
netUIListener.setOriginalData(resultStr);//儲存原始字元
responseBean = netRequest.getDataParser().parse(resultStr, type);
if (responseBean != null) {
netRequestStatus = NetUtils.NetRequestStatus.SUCCESS;
} else {
netRequestStatus = NetUtils.NetRequestStatus.SERVER_ERROR;
}
} else {
netRequestStatus = NetUtils.NetRequestStatus.NET_ERROR;
}
callback(netRequestStatus, responseBean);
}
}
網路請求引擎,實現類一般是各種網路框架okhttp,httpclient.
public interface NetEngine {
/**
* Init context.
*
* @param context the context
*/
void initContext(Context context);
NetResponseInfo request(NetParameter params, NetRequestConfig.Method method);
/**
* Add task tag.
*
* @param taskTag the task tag
*/
void addTaskTag(Object taskTag);
/**
* Cancel task.
*
* @param canceller the canceller
*/
void cancelTask(Canceller canceller);
}
/**
* 用okhttp網路框架實現{@link NetEngine}
*
* @version V1.0
*/
public class OkHttpNetEngine implements NetEngine {
/**
* The DEBUG TAG.
*/
public static final String TAG = OkHttpNetEngine.class.getSimpleName();
/**
* Instantiates a new Ok http net engine.
*
* @param context the context
*/
public OkHttpNetEngine(Context context) {
initContext(context);
}
/**
* Add task tag.
*
* @param taskTag the task tag
*/
@Override
public void addTaskTag(Object taskTag) {
this.taskTag = taskTag;
}
/**
* 任務TAG
*/
private Object taskTag;
/**
* @version V1.0
* @Title: Ok http excutor
* 2016.12.02
* @Title: Ok http excutor
*/
private static class OkHttpExcutor {
/**
* M ok http client.
*/
private static final OkHttpClient okHttpClient = new OkHttpClient();
/**
* 連線超時.
*/
private static final int CONNECT_TIME_OUT_MS = 60 * 1000;
/**
* 讀取超時.
*/
private static final int READ_TIME_OUT_MS = 60 * 1000;
static {
okHttpClient.setConnectTimeout(CONNECT_TIME_OUT_MS,
TimeUnit.MILLISECONDS);
okHttpClient.setWriteTimeout(READ_TIME_OUT_MS, TimeUnit.MILLISECONDS);
okHttpClient.setReadTimeout(READ_TIME_OUT_MS, TimeUnit.MILLISECONDS);
okHttpClient.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] x509Certificates = new X509Certificate[0];
return x509Certificates;
}
}}, new SecureRandom());
okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
/**
* Init persistent cookie store.
*
* @param context the context
*/
public static void initPersistentCookieStore(Context context) {
if (okHttpClient.getCookieHandler() == null) {
if (context != null) {
Context application = context.getApplicationContext();
if (application != null) {
okHttpClient.setCookieHandler(new CookieManager(
new PersistentCookieStore(application), CookiePolicy.ACCEPT_ALL));
}
}
}
}
/**
* Cancel task.
*
* @param taskTag the task tag
*/
public static void cancelTask(Object taskTag) {
if (taskTag != null) {
okHttpClient.cancel(taskTag);
}
}
/**
* Request by post net response info.
*
* @param params the params
* @param taskTag the task tag
* @param method the method
* @return the net response info
*/
public static NetResponseInfo requestByMethod(NetParameter params, Object taskTag, NetRequestConfig.Method method) {
NetResponseInfo netEventInfo = new NetResponseInfo();//返回資訊
Request.Builder builder = new Request.Builder();
if (taskTag != null) {
builder.tag(taskTag);
}
ResponseBody responseBody = null;
try {
FormEncodingBuilder formEncodingBuilder = new FormEncodingBuilder();
//請求引數拼裝
List<KeyValuePair> list = params.createParameters();
Request request =null;
switch (method){
case GET:
String url = params.getRequestURL();
if (list != null && !list.isEmpty()) {
url += "?"
+ URLEncodedUtils.format(list, "UTF-8");
}
request = builder.url(url).build();
break;
case DELETE:
if (list != null && !list.isEmpty()) {
for (KeyValuePair keyValuePair : list) {
formEncodingBuilder.add(keyValuePair.getKey(),
keyValuePair.getValue());
}
}
request = builder.url(params.getRequestURL())
.delete(formEncodingBuilder.build()).build();
break;
case POST:
if (list != null && !list.isEmpty()) {
for (KeyValuePair keyValuePair : list) {
formEncodingBuilder.add(keyValuePair.getKey(),
keyValuePair.getValue());
}
}
request = builder.url(params.getRequestURL())
.post(formEncodingBuilder.build()).build();
break;
case PUT:
if (list != null && !list.isEmpty()) {
for (KeyValuePair keyValuePair : list) {
formEncodingBuilder.add(keyValuePair.getKey(),
keyValuePair.getValue());
}
}
request = builder.url(params.getRequestURL())
.put(formEncodingBuilder.build()).build();
break;
default:
if (list != null && !list.isEmpty()) {
for (KeyValuePair keyValuePair : list) {
formEncodingBuilder.add(keyValuePair.getKey(),
keyValuePair.getValue());
}
}
request = builder.url(params.getRequestURL())
.post(formEncodingBuilder.build()).build();
break;
}
Call call = okHttpClient.newCall(request);
netEventInfo.setStartTime(String.valueOf(System.currentTimeMillis()));//網路耗時統計
Response response = call.execute();
netEventInfo.setEndTime(String.valueOf(System.currentTimeMillis()));//網路耗時統計
netEventInfo.setHttpCode(String.valueOf(response.code()));///網路返回狀態碼
if (response.isSuccessful()) {
netEventInfo.setSuccess(true);
responseBody = response.body();
if (responseBody != null) {
String reponseStr = responseBody.string();
if (!TextUtils.isEmpty(reponseStr)) {
//網路返回結果解碼
netEventInfo.setResult(params.decodeResponse(reponseStr));
}
}
}
} catch (Exception e) {
netEventInfo.setException(e.toString());//記錄網路請求錯誤
} finally {
try {
responseBody.close();
} catch (Exception e) {
}
}
return netEventInfo;
}
}
/**
* Init context.
*
* @param context the context
*/
@Override
public void initContext(Context context) {
if (context != null) {
OkHttpExcutor.initPersistentCookieStore(context);
}
}
@Override
public NetResponseInfo request(NetParameter params, NetRequestConfig.Method method) {
return OkHttpExcutor.requestByMethod(params, taskTag, method);
}
/**
* Cancel task.
*
* @param canceller the canceller
*/
@Override
public void cancelTask(Canceller canceller) {
if (canceller != null) {
OkHttpExcutor.cancelTask(canceller.getTaskTag());
}
}
private static final String POST = "POST";
private static final String GET = "GET";
private static final String PUT = "PUT";
private static final String DELETE = "DELETE";
}
有 請求了肯定有回撥啊,這個是必須的
public abstract class NetUIListener<T> {
/**
* M type.
*/
private Type mType;
/**
* Original data.
*/
private String originalData;
/**
* Gets original data.
*
* @return the original data
*/
public String getOriginalData() {
return originalData;
}
/**
* Sets original data.
*
* @param originalData the original data
*/
public void setOriginalData(String originalData) {
this.originalData = originalData;
}
/**
* Instantiates a new Ui listener.
*/
public NetUIListener() {
mType = getSuperclassTypeParameter(getClass());
}
/**
* Gets type.
*
* @return the type
*/
public Type getType() {
return mType;
}
/**
* Gets superclass type parameter.
*
* @param subclass the subclass
* @return the superclass type parameter
*/
private Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return parameterized.getActualTypeArguments()[0];
}
public NetRequestConfig.Method getMethod(){
return NetRequestConfig.Method.POST;
}
public abstract NetParameter createNetParams();
/**
* 在非主執行緒中組裝引數適用於耗時的任務
*/
public void assembleCommonParamsBeanBackground(){
}
/**
* SUCCESS:伺服器成功返回資料並GSON解析完成,業務處理
* SERVER_ERROR:系統錯誤(例如gson解析錯誤)
* NET_ERROR:網路錯誤
* UI執行緒執行
*
* @param bean the bean
* @param netRequestStatus the net request status
*/
public abstract void onComplete(T bean, NetUtils.NetRequestStatus netRequestStatus);
}
public abstract class CommonNetUIListener<T> extends NetUIListener<T> implements ConfigUrl{
@Override
public NetParameter createNetParams() {
return new CommonNetParameter(createUrl(),submitNetParams());
}
/**
* 提交網路請求引數
* return NULL,不傳送網路請求,也不會有結果回撥
* UI執行緒執行
*
* @return the common params bean
*/
public abstract List<KeyValuePair> submitNetParams();
}
網路返回資料解析類,具體可以實現 XML, JSON等格式的轉換
public interface NetDataParser {
/**
* Parse t.
*
* @param data the data
* @param classOfT the class of t
* @return the t
*/
Object parse(Object data, Type classOfT);
}
public class JsonDataParser implements NetDataParser {
/**
* Parse t.
*
* @param data the data
* @param classOfT the class of t
* @return the t
*/
@Override
public Object parse(Object data, Type classOfT) {
if (data != null && classOfT != null) {
if (data.getClass() != classOfT) {
return GsonUtil.fromJsonStringToCollection(
String.valueOf(data), classOfT);
} else {
return data;
}
}
return null;
}
可以說費勁九牛二虎之力實現一個很原始的網路框架。。。。哈哈