android移動開發學習筆記(二)神奇的Web API
本次分兩個大方向去講解Web Api,1、如何?Web Api?2、如何Android端如何調用Web Api?對於Web Api是什嗎?有什麼優缺點?為什麼用WebApi而不用Webservice?這些問題都不去解答,百度一下,關於這方面的資料很多,就不再去囉嗦。
一、如何在web端實現WebApi
(1)如何建立一個WebApi?
在上一章中,講到我們項目用的是.net 4.5,開發工具是Visual Studio 2012,在Visual Studio 2012中建立MVC4項目,選擇Web API,然後項目產生,如一、圖二、圖三所示, 和普通的MVC項目相比,它繼承了ApiController,然後我們運行一下項目,在瀏覽器裡輸入http://localhost:56091/api/values/get?id=5,四所示,即成功調用了項目預設寫的Get方法執行個體,有資料返回即表示調用成功!
(圖一)
(圖二)
(圖三)
(圖四)
(2)Get和Post資料?
(2.1) Get方法
具體什麼是Get就不再囉嗦了,可以自己百度查看, 使用 [HttpGet]標識,當然也可以不用加,只需要方法名用Get開頭,Get方法是使用Url參數傳遞的,不能接收實體參數,如:http://localhost:56091/api/values/get?id=5,id即是參數,當然也可以多參數,如:http://localhost:56091/api/values/get?id=5&name=tim ,預設參數使用[FromUri]
Get是有長度限制的,參數不能過多,而且參數暴露在外面,容易被人很方便的截取。
(2.2)Post方法
使用 [HttpPost]方式傳遞,當然也可以不用加,只需要方法名用Post開頭,Post方法可以使用Url傳遞參數,也可以用Body傳遞參數,預設參數使用[FromUri],可以加[FromBody]接收body裡傳遞的參數,但是有問題的是,我使用[FromBody]方式,參數為空白,根本接收不動值,上網查了資料,很多人遇到問題,不知道是不是Web Api本身的問題,無奈只好使用下面最原始的方式了,擷取Body的值了。
HttpContextBase context = (HttpContextBase)Request.Properties[MS_HttpContext];//擷取傳統context HttpRequestBase request = context.Request;//定義傳統request對象 string name = request.Form.Keys[0]; if (name == null) { name = request.Form[0]; }
另外Post的方法不能直接在瀏覽器裡敲地址擷取資料,調試起來不是很方便,所以用了一個工具,Firefox瀏覽器可以安裝一個外掛程式,叫Poster,如六所示,測試起來很方便。
(圖五)
(圖六)
(3)Json資料格式?
JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式,易於人閱讀和編寫,同時也易於機器解析和產生。
Json資料格式傳輸是目前介面資料轉送主流,本次我們的項目也是使用Json格式資料,我們所有的介面參數都是統一的參數名,後面跟的是Json格式字串,如:http://localhost:8010/api/MobileInfo/Get_Welcome? params=JsonString,這是介面的調用,介面返回結果也是Json格式。
如七所示,使用Newtonsoft.Json類庫,這是VS項目整合的類庫,可以很方便的使用JsonConvert.SerializeObject(value)方法,將object對象轉換為Json格式。
(圖七)
//step2:參數還原序列化 T transferObj = default(T); transferObj = Newtonsoft.Json.JsonConvert.DeserializeObject(JsonString);
(4) 路由的配置
如八所示,預設路由配置是這樣,只會找到Controller,不用根據Action去分配地址,所以相同Controller下只會找到Get方法或Post方法,不管你方法名是否相同,這樣很明顯不能滿足我們的需求,如果想以Action去標識地址,就用下面代碼配置:
config.Routes.MapHttpRoute( name: CommonApi, routeTemplate: api/{controller}/{action}/{id}, defaults: new { id = RouteParameter.Optional });
(圖八)
二、如何在Android端調用WebApi
(1)調用web Api的Get方法
public void getAnnouncement(final Object reqTag, final WSAnnouncementListCb cb) { //需要調用WebApi的Url地址 參數用UTF-8編碼 String url = Constants.WEB_BASE_URL + MobileInfo/Get_AnnouncementList?JsonString= + Utils.getEncodingParamsString((Object) UserManager.getInstance() .getLoginedUserInfo()); //使用Request對象,請求資料 Mdthod.Get WsAnnouncementListRsp.class接收結果的對象實體類 GsonRequest gsonRequest = new GsonRequest( Method.GET, url, WSAnnouncementListRsp.class, new Response.Listener() { @Override public void onResponse(WSAnnouncementListRsp rsp) { //返回的Json格式資料,經過還原序列化後的對象實體 if (cb != null) { cb.onResponse(Utils.stringToInteger(rsp.message.ResultCode), rsp); } } }, errorListener(true)); gsonRequest.setRequestTag(reqTag); RequestManager.addRequest(gsonRequest, reqTag); }
Android還原序列化Json的方法:
當然下面代碼中包含判斷Token是否到期,到期之後重新登入,因為判斷Token是否到期是每個App介面都可能要考慮的事情,所以就沒有刪除,以供大家參考。
//Response的時候,返回解析後的對象 protected Response parseNetworkResponse(NetworkResponse response) { try { //接收到的Json格式資料字串 String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));//如果有逸出字元就替換她 json = json.substring(1, json.length() - 1); json = json.replace(\, ); Log.I(L, Response type: + mClazz.getName() + Parsed Json Buffer: + json); //還原序列化Json資料 WSBaseResponse baseResponse = (WSBaseResponse) mGson.fromJson(json, mClazz); //判斷Token是否到期 if (Utils.stringToInteger(baseResponse.message.ResultCode) == Constants.ERR_TOKEN_INVALID) {// Log.I(L, get token status: + UserManager.getInstance().getTokenStatus());// if (UserManager.getInstance().getTokenStatus() != TOKEN_STATUS.TOKEN_GETTING) {// Log.I(L,set token status: + TOKEN_STATUS.TOKEN_EXPIRED);// UserManager.getInstance().setTokenStatus(TOKEN_STATUS.TOKEN_EXPIRED);// } synchronized (GsonRequest.class) { if (UserManager.getInstance().getTokenStatus() != TOKEN_STATUS.TOKEN_GETTING) { Log.I(L, relogin ...); RequestManager.addCachedRequest(this); UserManager.getInstance().relogin(new OnLoginListener() { @Override public void onLogin(int result, String message) { if (result == UserManager.LOGIN_RESULT_OK) { Log.I(L, Login suceesss); UserManager.getInstance().setTokenStatus(TOKEN_STATUS.TOKEN_OK); } else { Log.I(L,Login failed...); // Show login activity UserManager.getInstance().setTokenStatus(TOKEN_STATUS.TOKEN_FAIL); MyActivityManager.getInstance().finishAllActivity(); showLoginActivity(); } } }); } else { // Log.I(L, prepare resend request); // reSendRequest(); RequestManager.addCachedRequest(this); } } return Response.error(new TokenExpiredError()); } else { //返回泛型對象 return Response.success((T) baseResponse/* * mGson.fromJson(json, * mClazz) */, HttpHeaderParser.parseCacheHeaders(response)); } } catch (UnsupportedEncodingException e) { Log.E(L, response parse error: + mClazz.getName()); return Response.error(new ParseError(e)); } catch (JsonSyntaxException e) { Log.E(L, response parse error: + mClazz.getName()); return Response.error(new ParseError(e)); } }
(2)調用web Api的Post方法
放在Url裡的和Get方法一樣調用,只是傳參的時候,把Method.Get改為Method.Post方式,
因此主要講Post的Body方法
public void updateUserInfo(final Object reqTag, final WSUpdateUserInfoReq req, final WSUpdateUserInfoCb cb) { setUserIdAndTokenForReq(req); // post Url不帶任何參數 String url = Constants.WEB_BASE_URL + MobileInfo/Save_EmployeeInfo;//req是參數 GsonRequest gsonRequest = new GsonRequest( Method.POST, url,Utils.getEncodingParamsString((Object) req), WSCommonRsp.class, null, new Response.Listener() { @Override public void onResponse(WSCommonRsp rsp) { if (cb != null) { cb.onResponse(Utils.stringToInteger(rsp.message.ResultCode), rsp); } } }, errorListener(true)); gsonRequest.setRequestTag(reqTag); RequestManager.addRequest(gsonRequest, reqTag); }
以上就是App介面的實現和介面在Android中的調用方法,我提供的都是一些虛擬碼,主要是講解功能實現的思想和用到哪些重要的類方法。下章則正式學習Android開發,看一個零基礎的菜鳥如何快速上手做開發的。