Retrofit 解析 JSON 數(shù)據(jù)

轉(zhuǎn)載自:Retrofit 解析 JSON 數(shù)據(jù) - 簡書

Retro是一個(gè)類型安全的REST客戶端转捕,它可以直接解析JSON數(shù)據(jù)變成JAVA對(duì)象糖儡,甚至支持回調(diào)操作横漏,處理不同的結(jié)果俭尖,本文將以IP地址API數(shù)據(jù)解析為例幽勒,講解如何使用Retrofit

本文適用于2.0以下的版本,目前1.9還是主流焊虏,此文章將漸漸成為歷史

將要使用的網(wǎng)站

Retrofit

IP地址查詢站

JSON數(shù)據(jù)在線轉(zhuǎn)換

文章目錄

JSON數(shù)據(jù)如何轉(zhuǎn)成JAVA

Retrofit同步獲取方法

Retrofit異步回調(diào)方法

JSON數(shù)據(jù)如何轉(zhuǎn)成JAVA

打開了剛剛引用的API查詢網(wǎng)頁淡喜,那個(gè)網(wǎng)頁給了一串JSON數(shù)據(jù)的示例

{"code":0,"data":{"ip":"210.75.225.254","country":"\u4e2d\u56fd","area":"\u534e\u5317",

"region":"\u5317\u4eac\u5e02","city":"\u5317\u4eac\u5e02","county":"","isp":"\u7535\u4fe1",

"country_id":"86","area_id":"100000","region_id":"110000","city_id":"110000",

"county_id":"-1","isp_id":"100017"}}

根據(jù)數(shù)據(jù)的大意,我們可以考慮構(gòu)建一個(gè)JavaIP類

publicclassIP{privateintcode;privateData data;}

這個(gè)類中的Date類是十分麻煩的诵闭,所以我們考慮用工具直接生成

進(jìn)入JSON數(shù)據(jù)在線轉(zhuǎn)換

粘貼JSON代碼進(jìn)去炼团,在右邊的Source Type選擇JSON,Anotation Style選擇Gson涂圆,其他的選擇自行摸索们镜,我的配置如圖

Retrofit

注意服務(wù)器發(fā)送的區(qū)分大小寫與帶下劃線的數(shù)據(jù)可能無法識(shí)別,導(dǎo)致返回為NULL润歉,所以一定要勾選上Gson這個(gè)Anotation模狭,這個(gè)勾選后,你的POJO數(shù)據(jù)踩衩,以及Gson的jar包都可以完全混淆嚼鹉,是一種超級(jí)偷懶的寫法。

點(diǎn)擊下方的Jar驱富,就會(huì)生成源碼包锚赤,你可以直接扔到工程中或者改名為zip手動(dòng)折騰,注意代碼的有些注解(Annotation)可能在AS中無法通過編譯,刪除即可

HTTP GET簡介

請(qǐng)求指定的頁面信息褐鸥,并返回實(shí)體主體线脚,我們可以在http鏈接中加入path,key-value等參數(shù),從而得到具體的對(duì)象叫榕。

我們回到API網(wǎng)站浑侥,它告訴了我們它的API是通過HTTP GET方法獲取的,何為GET晰绎?簡單的說寓落,就是在請(qǐng)求的url中加入key-value參數(shù),發(fā)送給服務(wù)器荞下,這里的key是ip伶选,value是你要查詢的地址,比如202.202.33.33

http://ip.taobao.com/service/getIpInfo.php?ip=202.202.33.33

服務(wù)器根據(jù)你的GET請(qǐng)求尖昏,返回如下的JSON數(shù)據(jù)

{"code":0, "data":{? ? "country":"中國",? ? "country_id":"CN",? ? "area":"西南",? ? "area_id":"500000",? ? "region":"重慶市",? ? "region_id":"500000",? ? "city":"重慶市",? ? "city_id":"500000",? ? "county":"",? ? "county_id":"-1",? ? "isp":"教育網(wǎng)",? ? "isp_id":"100027",? ? "ip":"202.202.33.33"}}

接下來我們?nèi)绾问褂肦etrofit獲取并解析數(shù)據(jù)呢仰税,現(xiàn)在開始正式的使用

Retrofit同步獲取方法

這里的同步獲取方法是指以只獲得JAVA對(duì)象為目標(biāo),而不更新UI線程中的數(shù)據(jù)抽诉,異步是指獲取到數(shù)據(jù)后立刻回調(diào)肖卧,更新UI線程中的界面,我們先講簡單的同步,建議跟著官方Wiki一起看

打開Android Studio掸鹅,新建一個(gè)工程塞帐,添加網(wǎng)絡(luò)權(quán)限,Bulid.gradle添加如下依賴

//自行更新后面的版本號(hào)compile'com.squareup.retrofit:retrofit:1.7.1' compile'com.squareup.okhttp:okhttp-urlconnection:2.0.0' compile'com.squareup.okhttp:okhttp:2.0.0'

修改UI界面巍沙,里面放上一個(gè)EditText,一個(gè)Button,一些Textview葵姥,用于輸入和顯示UI數(shù)據(jù),這步略

寫IP工具類句携,用于封裝獲取獲取IP榔幸,這里的命名IPUtils比較吐槽,各位先忽視

publicclassIPUtils{//eg : http://ip.taobao.com/service/getIpInfo.php?ip=202.202.32.202staticfinalString? ENDPOINT ="http://ip.taobao.com/service";publicinterfaceTaobaoIPService{@GET("/getIpInfo.php")IPgetIp(@Query("ip")String ip);? ? }staticRestAdapter restAdapter =newRestAdapter.Builder()? ? ? ? ? ? .setEndpoint(ENDPOINT)//是否Debug.setLogLevel(RestAdapter.LogLevel.FULL)? ? ? ? ? ? .build();staticpublicTaobaoIPService taobaoIPService = restAdapter.create(TaobaoIPService.class); }

這個(gè)IPUtils首先建立了一個(gè)接口TaobaoIPService矮嫉,接著又創(chuàng)建了一個(gè)restAdapter削咆,最后用restAdapter實(shí)例化接口,我們要獲取IP的時(shí)候蠢笋,直接調(diào)用taobaoIPService中的getIp方法了拨齐,至于為什么我要寫這個(gè)接口?官網(wǎng)上有詳細(xì)的講解

現(xiàn)在只需要在Activity中調(diào)用getIp即可

IP ip = IPUtils.taobaoIPService.getIp("202.202.33.33");

就可以獲得所有的IP數(shù)據(jù)了昨寞,注意這個(gè)任務(wù)是網(wǎng)絡(luò)任務(wù)瞻惋,所以不要忘記給程序加入網(wǎng)絡(luò)權(quán)限,并且讓這個(gè)getIp在非UI線程中使用(比如最簡單的AsyncTask)援岩,之后如何使用IP數(shù)據(jù)就簡單了歼狼,操作第二步的UI組件即可

Retrofit異步回調(diào)方法

Retrofit的異步回調(diào)是指在獲取到數(shù)據(jù)后,立刻進(jìn)行UI的更新享怀,你不需要自己另外寫AsyncTask羽峰,代碼看上去簡潔,如果配合Dagger(一個(gè)Android注解框架添瓷,本文不討論)的使用就更加美了

建立一個(gè)工具類

publicclassIPUtils{//eg : http://ip.taobao.com/service/getIpInfo.php?ip=202.202.32.202staticfinalString? ENDPOINT ="http://ip.taobao.com/service";publicinterfaceTaobaoIPService{@GET("/getIpInfo.php")voidgetIp(@Query("ip")String ip, Callback callback);? ? }staticRestAdapter restAdapter =newRestAdapter.Builder()? ? ? ? ? ? .setEndpoint(ENDPOINT)? ? ? ? ? ? .setLogLevel(RestAdapter.LogLevel.FULL)? ? ? ? ? ? .build();publicstaticTaobaoIPService taobaoIPService =? ? ? ? ? ? restAdapter.create(TaobaoIPService.class); }

從代碼中可以看出TaobaoIPService中的方法getIp沒有返回值了梅屉,反而多了一個(gè)Callback,官方 Wiki是這么說的

On Android, callbacks will be executed on the main thread.

在我們結(jié)束了數(shù)據(jù)獲取后仰坦,無論是否成功履植,都將啟動(dòng)回調(diào),回調(diào)將在主線程(UI線程)執(zhí)行悄晃。

在Activity的使用

submitButton.setOnClickListener(newView.OnClickListener() {@OverridepublicvoidonClick(View view){? ? ? ? String query = editText.getText().toString();if(!query.isEmpty()) {//該組件能夠自動(dòng)啟動(dòng)Http線程玫霎,然后在回調(diào)中用main線程修改UI//詳情可以看“SYNCHRONOUS VS. ASYNCHRONOUS VS. OBSERVABLE”IPUtils.taobaoIPService.getIp(query,newCallback() {@Overridepublicvoidsuccess(IP ip, Response response){? ? ? ? ? ? ? ? ? ? textView_code.setText(String.valueOf(ip.getCode()));? ? ? ? ? ? ? ? ? ? textView_ip.setText(ip.getData().getIp());? ? ? ? ? ? ? ? ? ? textView_country.setText(ip.getData().getCountry());? ? ? ? ? ? ? ? ? ? textView_area.setText(ip.getData().getArea());? ? ? ? ? ? ? ? ? ? textView_region.setText(ip.getData().getRegion());? ? ? ? ? ? ? ? ? ? textView_city.setText(ip.getData().getCity());? ? ? ? ? ? ? ? ? ? textView_isp.setText(ip.getData().getIsp());? ? ? ? ? ? ? ? }@Overridepublicvoidfailure(RetrofitError error){? ? ? ? ? ? ? ? ? ? showToast("failure:"+ error.getKind());? ? ? ? ? ? ? ? }? ? ? ? ? ? });? ? ? ? }? ? } });

我們可以看出Callback重寫了2個(gè)方法,一個(gè)是成功妈橄,一個(gè)是失敗庶近。在成功(success)中,我們利用回調(diào)的數(shù)據(jù)眷蚓,直接進(jìn)行UI的更新

這里注意可能出現(xiàn)的內(nèi)存泄露鼻种,如果你是執(zhí)行耗時(shí)任務(wù),當(dāng)你退出activity后沙热,回調(diào)后可能會(huì)出現(xiàn)空指針異常叉钥。

對(duì)錯(cuò)誤以及異常的處理

可以看到罢缸,在剛剛的代碼中,我們僅僅輸出了錯(cuò)誤的種類投队,沒有個(gè)性化的輸出枫疆,作為客戶端我們應(yīng)該如何處理不同的錯(cuò)誤異常呢?我們先列舉用戶出錯(cuò)的情況敷鸦,常見的錯(cuò)誤種類如下

publicenumKind {/** An {@link IOException} occurred while communicating to

the server. */NETWORK,/** An exception was thrown while (de)serializing a body. */CONVERSION,/** A non-200 HTTP status code was received from the server. */HTTP,/**

* An internal error occurred while attempting to execute a

request. It is best practice to

* re-throw this exception so your application crashes.

*/UNEXPECTED? ? }

NETWORK:用戶沒有聯(lián)網(wǎng)息楔,這個(gè)簡單,你可以發(fā)一個(gè)Toast扒披,或者在提交數(shù)據(jù)前檢查網(wǎng)絡(luò)連接

CONVERSION:用戶輸入錯(cuò)誤的數(shù)據(jù)值依,比如1234,導(dǎo)致服務(wù)器返回錯(cuò)誤的數(shù)據(jù),使客戶度無法解析(CONVERSION)

{"code":1,"data":"invaild ip."}

對(duì)于這個(gè)錯(cuò)誤(CONVERSION),我們可以在本地用正則表達(dá)式在提交數(shù)據(jù)前對(duì)數(shù)據(jù)進(jìn)行簡單的驗(yàn)證,當(dāng)然如果服務(wù)器真的傳來了碟案,也沒什么愿险,你同樣只用發(fā)一個(gè)Toast,提示“重新填寫請(qǐng)求”即可

HTTP:處理這個(gè)錯(cuò)誤蟆淀,需要服務(wù)端與客戶端寫好技術(shù)文檔拯啦,或者使用Mock模擬所有的錯(cuò)誤,一般一個(gè)好的服務(wù)器是不會(huì)出現(xiàn)這個(gè)錯(cuò)誤的熔任,真的出現(xiàn)了話褒链,特例處理,比如常見的500,404錯(cuò)誤

UNEXPECTED:暫時(shí)沒見過

最后疑苔,我們寫出的failure應(yīng)該是這樣的甫匹,健壯高效

@Overridepublicvoidfailure(RetrofitError error){switch(error.getKind()) {caseNETWORK:? ? ? showToast("網(wǎng)絡(luò)錯(cuò)誤");break;caseCONVERSION:? ? ? showToast("重新輸入");break;caseHTTP://這里可以用Mockito模擬showToast("錯(cuò)誤代碼:"+ String.valueOf(error.getResponse().getStatus())? ? ? +"錯(cuò)誤原因:"+ error.getResponse().getReason());break;caseUNEXPECTED:? ? ? showToast("未知錯(cuò)誤");//TODO:寫入日志break;? }? showToast("failure:"+ error.getKind());}

在用界面看來,用戶得到了有效的錯(cuò)誤消息惦费,可以與開發(fā)作者溝通反饋兵迅。

PS1:POST操作

我目前有個(gè)開源的項(xiàng)目,圖片上傳用的就是Retrofit2.0的POST上傳薪贫,有興趣去看看吧恍箭。

Fork me on gitHub

PS2: Retrofit2.0

我在stackoverflow回答的關(guān)于Retrofit2.0的相關(guān)問題

使用RxJava與Retrofit2.0使用的實(shí)例:Retrofit 2.0 RxJava Sample

JW大神的文章

http://wuxiaolong.me/2016/01/15/retrofit/

后記

本文全完,謝謝觀看瞧省!本博客持續(xù)更新與搬運(yùn)國外大神的文章扯夭,有興趣的話不妨點(diǎn)一個(gè)收藏,另外我還維護(hù)著一個(gè)材料設(shè)計(jì)的專題鞍匾,歡迎收藏交洗。

推薦拓展閱讀

舉報(bào)文章

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

89145aa6a54e@火槍輝耀了我也是最近在學(xué)習(xí)這個(gè) 緩存今天看的 你可以看下這篇文章http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0115/3873.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市橡淑,隨后出現(xiàn)的幾起案子构拳,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件置森,死亡現(xiàn)場離奇詭異斗埂,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)暇藏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門蜜笤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人盐碱,你說我怎么就攤上這事』铮” “怎么了瓮顽?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長围橡。 經(jīng)常有香客問我暖混,道長,這世上最難降的妖魔是什么翁授? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任拣播,我火速辦了婚禮,結(jié)果婚禮上收擦,老公的妹妹穿的比我還像新娘贮配。我一直安慰自己,他們只是感情好塞赂,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布泪勒。 她就那樣靜靜地躺著,像睡著了一般宴猾。 火紅的嫁衣襯著肌膚如雪圆存。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天仇哆,我揣著相機(jī)與錄音沦辙,去河邊找鬼。 笑死讹剔,一個(gè)胖子當(dāng)著我的面吹牛油讯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辟拷,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼撞羽,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了衫冻?” 一聲冷哼從身側(cè)響起诀紊,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎隅俘,沒想到半個(gè)月后邻奠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笤喳,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年碌宴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了杀狡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡贰镣,死狀恐怖呜象,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碑隆,我是刑警寧澤恭陡,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站上煤,受9級(jí)特大地震影響休玩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜劫狠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一拴疤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧独泞,春花似錦呐矾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至孕惜,卻和暖如春愧薛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背衫画。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國打工毫炉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人削罩。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓瞄勾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親弥激。 傳聞我的和親對(duì)象是個(gè)殘疾皇子进陡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,726評(píng)論 25 707
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程,因...
    小菜c閱讀 6,362評(píng)論 0 17
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理微服,服務(wù)發(fā)現(xiàn)趾疚,斷路器,智...
    卡卡羅2017閱讀 134,626評(píng)論 18 139
  • 文/一念之間 此故事是“常走夜路必撞鬼”的結(jié)局篇 大紅和李發(fā)急匆匆地穿過荒墳地,此時(shí)已月上中天糙麦。 今晚的月亮好像半...
    一nian之間閱讀 424評(píng)論 2 1
  • 前情回顧: 那個(gè)嚷嚷著要睡我的男人辛孵。(一) 那個(gè)嚷嚷著要睡我的男人(二) 就是馬小武不說讓我走,我也要走赡磅。 這個(gè)地...
    月德閱讀 388評(píng)論 0 0