免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
Android Volley OkHttp3 Gson(Jackson)的封裝過(guò)程

前言

寒假學(xué)習(xí)了一下安卓的網(wǎng)絡(luò)通信部分,擴(kuò)展和封裝了volley,還是挺有意思的,所以寫(xiě)一篇博客來(lái)記錄一下整個(gè)歷程吧。大家都知道,安卓網(wǎng)絡(luò)通信有很多解決方案,比如HttpURLConnection,OkHttp,Android-async-http,Volley等,那為什么是Volley+OkHttp3+Gson(Jackson)?答案是這樣的,用volley來(lái)進(jìn)行網(wǎng)絡(luò)通信,用Okhttp3來(lái)處理Volley的底層HTTP請(qǐng)求,然后用Gson或者Jackson來(lái)解析json數(shù)據(jù),這樣封裝起來(lái)的庫(kù)已經(jīng)足夠應(yīng)付數(shù)據(jù)量小但通信頻繁的網(wǎng)絡(luò)操作了。下面會(huì)給出每個(gè)開(kāi)源庫(kù)的簡(jiǎn)介和地址(詳細(xì)介紹和使用請(qǐng)看官網(wǎng)),接著就進(jìn)行volley的簡(jiǎn)單擴(kuò)展和封裝,并且優(yōu)化部分代碼。


volley官方演講配圖

簡(jiǎn)介

  • Volley
    Google出品的一個(gè)簡(jiǎn)化網(wǎng)絡(luò)任務(wù)的庫(kù),負(fù)責(zé)處理請(qǐng)求、加載、緩存、線(xiàn)程、異步等等操作,能處理JSON格式的數(shù)據(jù),圖片,緩存,純文字,允許開(kāi)發(fā)者實(shí)現(xiàn)一些自定制服務(wù),適合進(jìn)行數(shù)據(jù)量不大,但通信頻繁的網(wǎng)絡(luò)操作,使用時(shí)最好再進(jìn)行簡(jiǎn)單的封裝。
    源碼
    非官方庫(kù)

  • OKhttp3
    Square出品的一個(gè)高效的HTTP客戶(hù)端,android 4.4以后已替換掉HttpURLConnection作為默認(rèn)的HTTP連接,OkHttp 3.x相對(duì)于2.x,在api和使用規(guī)范上有一些調(diào)整。
    官網(wǎng)
    源碼
    wiki

  • Gson
    Google開(kāi)發(fā)的用于轉(zhuǎn)換Java對(duì)象和Json對(duì)象的java庫(kù)
    源碼

  • Jackson
    在處理json大文件時(shí)解析性能明顯優(yōu)于Gson,如果應(yīng)用經(jīng)常需要傳輸較大的json文件則使用Jackson,小文件則使用Gson。還有阿里的fastjson也有其優(yōu)勢(shì),沒(méi)用過(guò),后面再說(shuō)= =
    Wiki


下載

Gradle

compile 'com.mcxiaoke.volley:library:1.0.19'compile 'com.squareup.okhttp3:okhttp:3.1.2'compile 'com.squareup.okio:okio:1.6.0'compile 'com.google.code.gson:gson:2.6.1'

簡(jiǎn)單使用

1、volley的使用一共三步驟,首先獲取一個(gè)全局的請(qǐng)求隊(duì)列對(duì)象,用來(lái)緩存所有的HTTP請(qǐng)求。

RequestQueue mRequestQueue = Volley.newRequestQueue(context);

2、然后新建一個(gè)請(qǐng)求,這里用JsonObjectRequest(JsonArrayRequest同理),(接口這里用mockarooMocky在線(xiàn)生成一個(gè))

JsonObjectRequest jsonObjectRequest = new JsonObjectRequest('http://www.mocky.io/v2/56c9d8c9110000c62f4e0bb0', null, new Response.Listener() { @Override public void onResponse(JSONObject response) { Log.d('mTAG', response.toString()); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e('mTAG', error.getMessage(), error); } });

3、最后添加請(qǐng)求到隊(duì)列中

mRequestQueue.add(jsonObjectRequest);

一個(gè)網(wǎng)絡(luò)請(qǐng)求操作就這樣方便簡(jiǎn)單,運(yùn)行,可以看到log打印如下

{'last_name':'Ramos','id':1,'first_name':'Roger','gender':'Male','ip_address':'194.52.112.37','email':'rramos0@gizmodo.com'}

自定義GsonRequest解析json

為了將上面的json數(shù)據(jù)解析為Java對(duì)象,我們使用Gson庫(kù),而velloy沒(méi)有支持Gson,所以我們仿照J(rèn)sonObjectRequest自己定義一個(gè)GsonRequest

public class GsonRequest extends Request { private final Listener mListener; private Gson mGson; private Class mClass; public GsonRequest(int method, String url, Class clazz, Listener listener, ErrorListener errorListener) { super(method, url, errorListener); mGson = new Gson(); mClass = clazz; mListener = listener; } public GsonRequest(String url, Class clazz, Listener listener, ErrorListener errorListener) { this(Method.GET, url, clazz, listener, errorListener); } @Override protected Response parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success(mGson.fromJson(jsonString, mClass), HttpHeaderParser.parseCacheHeaders(response));//用Gson解析返回Java對(duì)象 } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } } @Override protected void deliverResponse(T response) { mListener.onResponse(response);//回調(diào)T對(duì)象 }}

簡(jiǎn)單分析一下上面代碼,我們覆蓋了Request父類(lèi)的方法,在parseNetworkResponse中使用了Gson解析得到的jsonString, 然后在deliverResponse中再回調(diào)此T對(duì)象。但是,parseNetworkResponse中Gson的解析只適用單個(gè)json對(duì)象,如果是json數(shù)組呢?所以我們還需要定義一個(gè)TypeToken來(lái)提供對(duì)復(fù)雜類(lèi)型的支持。

還有一點(diǎn),就是這個(gè)GsonRequest類(lèi)只適合get請(qǐng)求,如果是post請(qǐng)求則會(huì)去其父類(lèi)Request中尋找post參數(shù)Params,所以我們?cè)俑采w一下父類(lèi)的getParams()方法,并且讓其支持在構(gòu)造器中直接傳入Params。
具體看一下代碼,修改如下

public class GsonRequest extends Request { private final Listener mListener; private static Gson mGson = new Gson(); private Class mClass; private Map mParams;//post Params private TypeToken mTypeToken; public GsonRequest(int method, Map params, String url, Class clazz, Listener listener, ErrorListener errorListener) { super(method, url, errorListener); mClass = clazz; mListener = listener; mParams = params; } public GsonRequest(int method, Map params, String url, TypeToken typeToken, Listener listener, ErrorListener errorListener) { super(method, url, errorListener); mTypeToken = typeToken; mListener = listener; mParams = params; } //get public GsonRequest(String url, Class clazz, Listener listener, ErrorListener errorListener) { this(Method.GET, null, url, clazz, listener, errorListener); } public GsonRequest(String url, TypeToken typeToken, Listener listener, ErrorListener errorListener) { this(Method.GET, null, url, typeToken, listener, errorListener); } @Override protected Map getParams() throws AuthFailureError { return mParams; } @Override protected Response parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); if (mTypeToken == null) return Response.success(mGson.fromJson(jsonString, mClass), HttpHeaderParser.parseCacheHeaders(response));//用Gson解析返回Java對(duì)象 else return (Response) Response.success(mGson.fromJson(jsonString, mTypeToken.getType()), HttpHeaderParser.parseCacheHeaders(response));//通過(guò)構(gòu)造TypeToken讓Gson解析成自定義的對(duì)象類(lèi)型 } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } } @Override protected void deliverResponse(T response) { mListener.onResponse(response); }}

定義好以后,我們就可以來(lái)new一個(gè)GsonRequest請(qǐng)求了。一步步來(lái),先根據(jù)網(wǎng)絡(luò)傳輸?shù)膉son字段來(lái)定義一個(gè)實(shí)體類(lèi),重新看一下剛才運(yùn)行打印出來(lái)的數(shù)據(jù)

{'last_name':'Ramos','id':1,'first_name':'Roger','gender':'Male','ip_address':'194.52.112.37','email':'rramos0@gizmodo.com'}

我們可以先取json數(shù)據(jù)中的first_name,last_name和gender作為Person類(lèi)的屬性

實(shí)體類(lèi)Person

public class Person { private String gender; private String first_name; private String last_name; public void setGender(String gender) {this.gender = gender;} public String getGender() { return this.gender;} public void setFirst_name(String first_name) {this.first_name = first_name;} public String getFirst_name() {return this.first_name;} public void setLast_name(String last_name) {this.last_name = last_name;} public String getLast_name() {return this.last_name;}}

然后新建一個(gè)GsonRequest,可以看到,onResponse回調(diào)方法直接返回了一個(gè)person對(duì)象,打印其數(shù)據(jù)驗(yàn)證一下

GsonRequest gsonRequest = new GsonRequest( 'http://www.mocky.io/v2/56c9d8c9110000c62f4e0bb0', Person.class, new Response.Listener() { @Override public void onResponse(Person person) { Log.d(TAG, 'first_name: ' + person.getFirst_name()); Log.d(TAG, 'last_name: ' + person.getLast_name()); Log.d(TAG, 'gender: ' + person.getGender()); mTextview.setText('first_name: ' + person.getFirst_name() + '\n' + 'last_name: ' + person.getLast_name() + '\n' + 'gender: ' + person.getGender()); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e(TAG, error.getMessage(), error); } }); //添加請(qǐng)求到隊(duì)列 mRequestQueue.add(gsonRequest);

打印的結(jié)果當(dāng)然是對(duì)的,我就不貼了。
好,先休息一下~

嗯,接著說(shuō),如果應(yīng)用經(jīng)常要傳輸大文件,那么最好是使用Jackson庫(kù)解析json,因?yàn)樗萭son更快,JacksonRequest的定義也同樣道理,貼上代碼

public class JacksonRequest extends Request { private final Listener mListener; private static ObjectMapper objectMapper = new ObjectMapper(); private Class mClass; private TypeReference mTypeReference;//提供解析復(fù)雜JSON數(shù)據(jù)支持 public JacksonRequest(int method, String url, Class clazz, Listener listener, ErrorListener errorListener) { super(method, url, errorListener); mClass = clazz; mListener = listener; } public JacksonRequest(int method, String url, TypeReference typeReference, Listener listener, ErrorListener errorListener) { super(method, url, errorListener); mTypeReference = typeReference; mListener = listener; } public JacksonRequest(String url, Class clazz, Listener listener, ErrorListener errorListener) { this(Method.GET, url, clazz, listener, errorListener); } public JacksonRequest(String url, TypeReference typeReference, Listener listener, ErrorListener errorListener) { super(Method.GET, url, errorListener); mTypeReference = typeReference; mListener = listener; } @Override protected Response parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); Log.v('mTAG', 'json'); if (mTypeReference == null)//使用Jackson默認(rèn)的方式解析到mClass類(lèi)對(duì)象 return (Response) Response.success( objectMapper.readValue(jsonString, TypeFactory.rawClass(mClass)), HttpHeaderParser.parseCacheHeaders(response)); else//通過(guò)構(gòu)造TypeReference讓Jackson解析成自定義的對(duì)象類(lèi)型 return (Response) Response.success(objectMapper.readValue(jsonString, mTypeReference), HttpHeaderParser.parseCacheHeaders(response)); } catch (Exception e) { return Response.error(new ParseError(e)); } } @Override protected void deliverResponse(T response) { mListener.onResponse(response); }}

因?yàn)轫?xiàng)目中我使用的是Gson,所以沒(méi)有把Jackson庫(kù)一起導(dǎo)入,如果要使用的話(huà)當(dāng)然是二選一了,而不是一起使用,不然項(xiàng)目apk文件該有多大啊


加載圖片

volley還有加載網(wǎng)絡(luò)圖片的功能,我們可以new一個(gè)ImageRequest來(lái)獲取一張網(wǎng)絡(luò)的圖片,不過(guò)它并沒(méi)有做緩存處理,所以我們用ImageLoader(volley.toolbox.ImageLoader),volley內(nèi)部實(shí)現(xiàn)了磁盤(pán)緩存,不過(guò)沒(méi)有內(nèi)存緩存,我們可以自己來(lái)定義。
1.新建一個(gè)ImageLoader,設(shè)置ImageListener,然后在get方法中傳入url,看代碼吧

ImageLoader imageLoader = new ImageLoader(mRequestQueue, new MyImageCache());ImageLoader.ImageListener listener = ImageLoader.getImageListener(mImageview, R.mipmap.ic_default, R.mipmap.ic_error); imageLoader.get('https://d262ilb51hltx0.cloudfront.net/max/800/1*dWGwx6UUjc0tocYzFNBLEw.jpeg', listener, 800, 800);

2.為了實(shí)現(xiàn)圖片的內(nèi)存緩存,我們使用LruCache來(lái)實(shí)現(xiàn),自定義一個(gè)MyImageCache類(lèi)繼承自ImageCache,然后其構(gòu)造方法中new一個(gè)最大為8M的LruCache

public class MyImageCache implements ImageLoader.ImageCache { private LruCache mCache; public MyImageCache() { int maxSize = 8 * 1024 * 1024; mCache = new LruCache(maxSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { //getRowBytes()返回圖片每行的字節(jié)數(shù),乘以高度得到圖片的size return bitmap.getRowBytes() * bitmap.getHeight(); } }; } @Override public Bitmap getBitmap(String url) { return mCache.get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { mCache.put(url, bitmap); } }

添加OkHttp

我們已經(jīng)實(shí)現(xiàn)了volley+Gson了,如果要使用OkHttp作為傳輸層,我們只需要在構(gòu)建 Volley 的請(qǐng)求隊(duì)列對(duì)象requestQueue時(shí)做一下改變,將OkHttp3Stack作為參數(shù)傳進(jìn)去。OkHttp3Stack具體的實(shí)現(xiàn)看一下鏈接 代碼

mRequestQueue = Volley.newRequestQueue(context, new OkHttp3Stack(new OkHttpClient()));

二次封裝

最后我們可以把volley的使用封裝成一個(gè)VolleyManager,代碼太長(zhǎng),見(jiàn)這里。
或者也可以把volley的請(qǐng)求操作提取出來(lái)放到Application中,這樣整個(gè)app就只用一個(gè)請(qǐng)求隊(duì)列對(duì)象。

public class App extends Application { public static final String TAG = 'App'; public RequestQueue mRequestQueue;//請(qǐng)求隊(duì)列 private ImageLoader mImageLoader; private static App mInstance; @Override public void onCreate() { super.onCreate(); mInstance = this; } public static synchronized App getInstance() { return mInstance; } public RequestQueue getRequestQueue() { if (mRequestQueue == null) { mRequestQueue = Volley.newRequestQueue(getApplicationContext()); } return mRequestQueue; } public ImageLoader getImageLoader() { getRequestQueue(); if (mImageLoader == null) { mImageLoader = new ImageLoader(this.mRequestQueue, new MyImageCache()); } return this.mImageLoader; } public void addRequest(Request req, String tag) { req.setTag(tag); getRequestQueue().add(req); } public void addRequest(Request req) { req.setTag(TAG); getRequestQueue().add(req); } public void cancelRequests(Object tag) { if (mRequestQueue != null) { mRequestQueue.cancelAll(tag); } }}

優(yōu)化

1.上面加載圖片MyImageCache類(lèi)的圖片緩存大小是固定的,改成這個(gè)可以實(shí)現(xiàn)動(dòng)態(tài)地分配緩存。

public class LruBitmapCache extends LruCache implements ImageCache { public LruBitmapCache(int maxSize) { super(maxSize); } public LruBitmapCache(Context ctx) { this(getCacheSize(ctx)); } @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } @Override public Bitmap getBitmap(String url) { return get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { put(url, bitmap); } // Returns a cache size equal to approximately three screens worth of images. public static int getCacheSize(Context ctx) { final DisplayMetrics displayMetrics = ctx.getResources(). getDisplayMetrics(); final int screenWidth = displayMetrics.widthPixels; final int screenHeight = displayMetrics.heightPixels; // 4 bytes per pixel final int screenBytes = screenWidth * screenHeight * 4; return screenBytes * 3; }}

2.在自定義的GsonRequest類(lèi)里,我們可以通過(guò)在其構(gòu)造器中添加 setMyRetryPolicy() 方法來(lái)實(shí)現(xiàn)請(qǐng)求超時(shí)時(shí)間的定制。

private void setMyRetryPolicy() { setRetryPolicy(new DefaultRetryPolicy(30000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

補(bǔ)充

忘了說(shuō)jackson的導(dǎo)入了= =,為了避免重復(fù)入坑,補(bǔ)充一下Jackson的下載

compile 'com.fasterxml.jackson.core:jackson-core:2.7.1'compile 'com.fasterxml.jackson.core:jackson-annotations:2.7.1'compile 'com.fasterxml.jackson.core:jackson-databind:2.7.1'

記得還要添加一下packagingOptions,因?yàn)閖ackson-core和jackson-databind有重復(fù)的文件,重復(fù)加載會(huì)報(bào)錯(cuò)。

android{ ... packagingOptions { exclude 'META-INF/NOTICE' // will not include NOTICE file exclude 'META-INF/LICENSE' // will not include LICENSE file }}

最后

如果這種解決方案還不滿(mǎn)足,還有一種更為強(qiáng)大的,Retrofit+OkHttp,都是Square公司出品,然后圖片加載再選擇Square的Picasso(或者谷歌推薦的Glide、Facebook的Fresco)。而且,Retrofit還支持RxJava,可以使異步操作的代碼更加簡(jiǎn)潔。這些搭配起來(lái)就是網(wǎng)絡(luò)的神裝了。不過(guò)Retrofit和RxJava我都沒(méi)深入研究過(guò),先打好基礎(chǔ)再說(shuō),以后有時(shí)間再看看。


代碼已經(jīng)放上github了,可能有不完善的地方,歡迎一起交流學(xué)習(xí)
代碼地址


著作權(quán)歸作者所有

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Android網(wǎng)絡(luò)框架Volley
Android使用Volley上傳文件
Volley介紹
Android Volley框架的幾種post提交請(qǐng)求方式
關(guān)于Volley解析出現(xiàn)中文亂碼現(xiàn)象的完美解決方案
java.lang.IllegalStateException: closed
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服