Android中volley封装实践记录
程序员文章站
2022-03-08 17:17:29
前言
在项目中一般使用使用volley方式如下,用起来给人一种很乱的感觉,于是一种盘它的想法油然而生。
public void get() {
strin...
前言
在项目中一般使用使用volley方式如下,用起来给人一种很乱的感觉,于是一种盘它的想法油然而生。
public void 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 @override public 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 @override protected 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 */ @override public void addmarker(string tag) { super.addmarker(tag); cachehit = tag.equals("cache-hit"); } @override protected 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)); } } @override protected void deliverresponse(tresponse response) { listener.onresponse(response); } @override protected 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() { } @override public 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"); @override public 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配置支持缓存,并设定好缓存时间,否则无法生效。
最后贴一张效果图:
图片发自简书app
到此结束,后期还会进行优化,代码在[github] ( ())。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。