Android volley封装实践
在项目中一般使用使用volley方式如下,用起来给人一种很乱的感觉,于是一种盘它的想法油然而生。
”’
private void volley_Get(){
String url = "https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=......"; StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String s) { Toast.makeText(MainActivity.this,s,Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Toast.makeText(MainActivity.this,volleyError.toString(),Toast.LENGTH_SHORT).show(); } }); request.setTag("abcGet"); MyApplication.getHttpQueues().add(request);}
”’
首先看一下我封装后的使用例子,假如你觉得然并软即可以左滑退出了。(我的文章有左滑自动关注效果哈哈)
”’
private void initData() {
NewsApi.getInfo(new NetCallback<News>() {
@Override
public void OnSuccess(final News result) {
mAdapter.setData(result.getResult().getData());
}
@Override public void OnError(RestfulError error) { } });}
”’
有没有看起来很舒服的感觉。好吧,让我开始盘它吧!
1.首先我先去写了一个基类,用来创立一个新的request并把它加入到volley内部封装的请求队列中,代码如下:
”’
public abstract class AuthenticatedRequestBase<T> extends Request<T> {
private final static String TAG = “AuthenticatedRequestBase”;
private static final int TIME_OUT = 30000;
private static final int MAX_RETRIES = 1;
private static final float BACKOFF_MULT = 2f;
protected Context mContext;
protected RequestQueue mRequestQueue;
/** * 创立新的请求,并把请求加入到请求队列requestQueue中 * * @param method * @param url * @param cache * @param errorListener */@SuppressLint("LongLogTag")public AuthenticatedRequestBase(int method, String url, boolean cache, Response.ErrorListener errorListener) { super(method, url, errorListener); //this.setShouldCache(cache); this.setRetryPolicy(new DefaultRetryPolicy( TIME_OUT, MAX_RETRIES, BACKOFF_MULT)); mRequestQueue = YZ.getInstance().getRequestQueue(); if (mRequestQueue == null) { throw new IllegalArgumentException("mRequestQueue can't be null"); } mContext = YZ.getInstance().getContext(); if (mContext == null) { throw new IllegalArgumentException("mContext can't be null"); } //假如重新发出服务器请求的时候,需要清理之前的缓存。 if (!cache) { Cache volleyCache = mRequestQueue.getCache(); Cache.Entry cacheEntry = volleyCache.get(url); if (cacheEntry != null) { volleyCache.remove(url); Log.d(TAG, "remove volley cache:" + url); } } mRequestQueue.add(this);}/** * 重写这个方法,可以在http请求头里面加入token,用户端能接受的数据类型 * * @return * @throws AuthFailureError */@CallSuper@Overridepublic Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> headers = new HashMap<>(); String token = "............"; //headers.put("Authorization", "bearer " + token); //针对Get方法,申明接受的enum类型 // headers.put("Accept", "charset=utf-8"); return headers;}/** * 网络错误问题统一解决 * * @param volleyError * @return */@CallSuper@Overrideprotected VolleyError parseNetworkError(VolleyError volleyError) { return super.parseNetworkError(volleyError);}
}
”’
代码注释比较清晰,就不在赘述。
2.以get方法为例,新建一个GetRequest去继承这个基类,并出解析结果:
”’
public class GetRequest<TResponse> extends AuthenticatedRequestBase<TResponse> {
private final Response.Listener<TResponse> listener;private final Class<TResponse> clazz;private final static String TAG = "GetRequest";private String mUrl;private NetCallback<TResponse> cb;private boolean cacheHit;public GetRequest(String url, Class<TResponse> clazz, boolean cache, NetCallback<TResponse> callback) { super(Request.Method.GET, url, cache, callback.getErrorListener()); this.listener = callback.getSuccessListener(); this.clazz = clazz; this.mUrl = url; this.cb = callback; //无网络时300ms后返回callback if (!NetUtils.isConnect(mContext) && mRequestQueue.getCache().get(url) == null) { Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { cb.OnNetworkOff(); } }, 300); }}/** * 这个是缓存的标记,与本地缓存相关 * @param tag */@Overridepublic void addMarker(String tag) { super.addMarker(tag); cacheHit = tag.equals("cache-hit");}@Overrideprotected Response<TResponse> parseNetworkResponse(NetworkResponse response) { Gson gson = new Gson(); //无网络时,使用本地缓存,通过url去匹配缓存,volley sdk是通过url创立不同的文件来实现缓存的 if (!NetUtils.isConnect(mContext) && mRequestQueue.getCache().get(mUrl) != null) { String json = new String(mRequestQueue.getCache().get(mUrl).data); Log.d(TAG, "url==" + mUrl + ",json" + json); cb.fResponseCacheStatus = ResponseCacheStatus.StaleFromCache; return Response.success(gson.fromJson(json, clazz), parseCacheHeaders(response)); } //数据能否有升级 try { if (response.statusCode == 304) { //服务端返回缓存数据 cb.fResponseCacheStatus = ResponseCacheStatus.NotModifiedFromServer; } else if (response.statusCode == 200) { if (cacheHit) { //使用本地缓存 cb.fResponseCacheStatus = ResponseCacheStatus.FreshFromCache; } else { //使用服务端升级数据 cb.fResponseCacheStatus = ResponseCacheStatus.NewFromServer; } } else { cb.fResponseCacheStatus = ResponseCacheStatus.NewFromServer; } Log.d(TAG, "fResponseCacheStatus = " + cb.fResponseCacheStatus); String json = new String(response.data, parseCharset(response.headers)); return Response.success(gson.fromJson(json, clazz), parseCacheHeaders(response)); } catch (UnsupportedEncodingException | JsonSyntaxException e) { return Response.error(new ParseError(e)); }}@Overrideprotected void deliverResponse(TResponse response) { listener.onResponse(response);}@Overrideprotected VolleyError parseNetworkError(VolleyError volleyError) { return super.parseNetworkError(volleyError);}
}
”’
3.上面只做了返回成功的解决方式,返回失败时由NetCallback内部统一解决:
”’
@UiThread
public abstract class NetCallback<TResponse> {
public ResponseCacheStatus fResponseCacheStatus = ResponseCacheStatus.NewFromServer;
private String TAG = this.getClass().getSimpleName();
public boolean enableAutomaticToastOnError = true;
public NetCallback() {}public NetCallback(boolean enableAutomaticToastOnError) { this.enableAutomaticToastOnError = enableAutomaticToastOnError;}public abstract void OnSuccess(TResponse result);public abstract void OnError(RestfulError error);public void OnNetworkOff() { //do nothing ,use it according to requirement}public Response.Listener<TResponse> getSuccessListener() { return new Response.Listener<TResponse>() { @Override public void onResponse(TResponse result) { OnSuccess(result); } };}public Response.ErrorListener getErrorListener() { return new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { if (volleyError instanceof TimeoutError) { Log.e(TAG, "networkResponse == null"); //volley TimeoutError OnError(new RestfulError()); } if (volleyError.networkResponse != null) { int statusCode = volleyError.networkResponse.statusCode; String errorMessage = new String(volleyError.networkResponse.data); switch (statusCode) { case 401: //post a Permission authentication failed event break; default: Log.d(TAG, "errorMessage =" + errorMessage); try { RestfulError error = new Gson().fromJson(errorMessage, RestfulError.class); if (enableAutomaticToastOnError && error.getCode() != null) { //toast(error.ExceptionMessage); //toast it in main thread } OnError(error); } catch (Exception e) { OnError(new RestfulError()); Log.d(TAG, "e =" + e.toString()); } break; } } } };}
}
”’
4.注意到没有,在AuthenticatedRequestBase内部有一个环境类YZ,主要负责获取项目主程序中的context和请求队列:
”’
public class YZ implements AppRequestQueue {
private static final int DEFAULT_VOLLEY_CACHE_SIZE = 100 * 1024 * 1024;
private Context context;
private int cacheSize;
private YZ() {}@Overridepublic RequestQueue getRequestQueue() { return Volley.newRequestQueue(context, cacheSize);}public Context getContext() { return context;}private static class SingletonHolder { private static YZ instance = new YZ();}public static YZ getInstance() { return SingletonHolder.instance;}/** * need a app context * * @param appContext */public void init(final Context appContext) { init(appContext, DEFAULT_VOLLEY_CACHE_SIZE);}/** * @param appContext * @param cacheSize */public void init(final Context appContext, final int cacheSize) { this.context = appContext; this.cacheSize = cacheSize;}
}
”’
这个类需要在app的application中初始化:
”’
public class BaseApp extends Application {
public String TAG = this.getClass().getSimpleName();public static Context applicationContext;public static Executor threadPool;public static final int THREAD_POOL_SIZE = 3;public static final boolean isDebug = BuildConfig.BUILD_TYPE.equals("debug");@Overridepublic void onCreate() { super.onCreate(); applicationContext = getApplicationContext(); threadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE); initNet();}private void initNet() { YZ.getInstance().init(this);}public Context getInstance() { return applicationContext;}
}
”’
4.现在可以开始外部封装啦。
”’
public class NewsApi {
public static void getInfo(NetCallback<News> callback) { new GetRequest<>(INetConstant.NEWS, News.class, true, callback);}
}
”’
还有一点,volley的缓存实现需要服务端配合在http请求的Cache-control: max-age配置支持缓存,并设定好缓存时间,否则无法生效。
最后贴一张效果图:
到此结束,后期还会进行优化,代码在 daydaydate/sample。感谢阅读,觉得不错的话点赞哦!
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Android volley封装实践