Android 輕鬆實現網絡交互模板

看完本文,您可以學到:


1.Android與後臺交互的模板化方法


2.JSON的使用

3.檢查網絡連接

4.AsyncTask的使用

我們簡單的以登錄爲例,來實現整個的流程。話不多說,先來看看效果圖:




一、通用類的編寫


首先,既然要實現交互模板化,最重要的就是要提取出儘可能多的可複用代碼。無論是與後臺進行什麼操作,判斷網絡是否正常連接、發送請求後得到數據、網絡異常時的錯誤信息提示都是必不可少的。所以我們編寫一個通用的CallService類:

[java] view plaincopy

  1. /** 

  2.  * Created by Hyman on 2015/6/11. 

  3.  */  

  4. public class CallService {  

  5.   

  6.     /** 

  7.      * check net connection before call 

  8.      * 

  9.      * @param context 

  10.      * @return 

  11.      */  

  12.     private static boolean checkNet(Context context) {  

  13.         ConnectivityManager connectivity = (ConnectivityManager) context  

  14.                 .getSystemService(Context.CONNECTIVITY_SERVICE);  

  15.         if (connectivity != null) {  

  16.             // 獲取網絡連接管理的對象  

  17.             NetworkInfo info = connectivity.getActiveNetworkInfo();  

  18.             if (info != null && info.isConnected()) {  

  19.                 // 判斷當前網絡是否已經連接  

  20.                 if (info.getState() == NetworkInfo.State.CONNECTED) {  

  21.                     return true;  

  22.                 }  

  23.             }  

  24.         }  

  25.         return false;  

  26.     }  

  27.   

  28.     /** 

  29.      * call service by net 

  30.      * 

  31.      * @param urlString url 

  32.      * @param content   a string of json,params 

  33.      * @return the result,a string of json 

  34.      */  

  35.     public static String call(String urlString, String content, Context context) {  

  36.         if (!checkNet(context)) {  

  37.             return null;  

  38.         }  

  39.         try {  

  40.             URL url = new URL(urlString);  

  41.             HttpURLConnection conn = (HttpURLConnection) url.openConnection();  

  42.             conn.setConnectTimeout(5000);  

  43.             conn.setDoOutput(true);  

  44.             conn.setRequestMethod("POST");  

  45.             conn.setRequestProperty("User-Agent""Fiddler");  

  46.             conn.setRequestProperty("Content-Type""application/json");  

  47.             conn.setRequestProperty("Charset""utf-8");  

  48.             OutputStream os = conn.getOutputStream();  

  49.             os.write(content.getBytes());  

  50.             os.close();  

  51.             int code = conn.getResponseCode();  

  52.             if (code == 200) {  

  53.                 BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));  

  54.                 String retData;  

  55.                 String responseData = "";  

  56.                 while ((retData = in.readLine()) != null) {  

  57.                     responseData += retData;  

  58.                 }  

  59.                 in.close();  

  60.                 return responseData;  

  61.             }  

  62.         } catch (MalformedURLException e) {  

  63.             e.printStackTrace();  

  64.         } catch (UnsupportedEncodingException e) {  

  65.             e.printStackTrace();  

  66.         } catch (ProtocolException e) {  

  67.             e.printStackTrace();  

  68.         } catch (IOException e) {  

  69.             e.printStackTrace();  

  70.         }  

  71.         return null;  

  72.     }  

  73.   

  74.     public static void showNetErr(Context context){  

  75.         new AlertDialog.Builder(context)  

  76.                 .setTitle("網絡錯誤")  

  77.                 .setMessage("網絡連接失敗,請確認網絡連接")  

  78.                 .setPositiveButton("確定"new DialogInterface.OnClickListener() {  

  79.                     @Override  

  80.                     public void onClick(DialogInterface arg0, int arg1) {  

  81.   

  82.                     }  

  83.                 }).show();  

  84.     }  

  85.       

  86. }  


其中,判斷網絡連接狀態是藉助Android系統提供的ConnectivityManager的方法實現的,藉助這個類我們還可以獲取更多的連接狀態信息,包括當前是用流量還是WIFI等等。


然後,在調用本類核心方法call()時,傳入了三個參數,一個是後臺服務的url路徑,一個是已經組裝好的參數,第三個是上下文context。

在這個方法中,我們先去判斷網絡連接,未連接就直接返回空。否則就使用HttpURLConnection方法向服務器發送請求,再把服務器的返回值返回給調用者。


另一個showNetErr方法就只是簡單地跳出一個對話框進行提示。



二、利用Json以及AsyncTask進行交互


我們都知道,在安卓中進行網絡操作等等這些耗時的操作,都不能在主線程(即UI線程中)操作,所以我們利用安卓提供的異步機制 AsyncTask(或者也可以自己寫new Thread + Handler)來進行網絡操作。還不瞭解AsyncTask用法的朋友可以看我的另一篇博客 Android AsyncTask詳解

我們以登錄爲例:

[java] view plaincopy

  1. /** 

  2.  * Created by Hyman on 2015/6/11. 

  3.  */  

  4.   

  5. public class Login {  

  6.   

  7.     private static final String urlString = GetServerUrl.getUrl() + "index.php?r=period/login";  

  8.     private static final String TAG = "Login";  

  9.   

  10.     private ProgressBar progressBar;  

  11.     private Context context;  

  12.   

  13.     private String userName;  

  14.     private String password;  

  15.   

  16.     public Login( Context context,ProgressBar progressBar) {  

  17.         this.progressBar=progressBar;  

  18.         this.context = context;  

  19.     }  

  20.   

  21.     public void login(String userName,String password) {  

  22.         Log.i(TAG, "call login");  

  23.         this.userName=userName;  

  24.         this.password=password;  

  25.         new LoginTask().execute();  

  26.     }  

  27.   

  28.     class LoginTask extends AsyncTask<Void, Void, String> {  

  29.         @Override  

  30.         protected String doInBackground(Void... params) {  

  31.             JSONObject tosendsObject = new JSONObject();  

  32.             Log.i(TAG, "start put json!");  

  33.             try {  

  34.                 //add account info  

  35.                 tosendsObject.put("username", userName);  

  36.                 tosendsObject.put("password", password);  

  37.             } catch (JSONException e) {  

  38.                 e.printStackTrace();  

  39.             }  

  40.             //change json to String  

  41.             String content = String.valueOf(tosendsObject);  

  42.             Log.i(TAG, "send :" + content);  

  43.             String responseData = CallService.call(urlString, content,context);  

  44.             if(responseData==null || responseData.equals("")){  

  45.                 return null;  

  46.             }  

  47.             Log.i(TAG, "res:" + responseData);  

  48.             JSONObject resultObject = null;  

  49.             String result=null;  

  50.             try {  

  51.                 resultObject = new JSONObject(responseData);  

  52.                 result = resultObject.getString("result");  

  53.                 Log.i(TAG, "result:" + result);  

  54.             } catch (JSONException e) {  

  55.                 e.printStackTrace();  

  56.             }  

  57.             return result;  

  58.         }  

  59.   

  60.         @Override  

  61.         protected void onPreExecute() {  

  62.             progressBar.setVisibility(View.VISIBLE);    //show the progressBar  

  63.             super.onPreExecute();  

  64.         }  

  65.   

  66.         @Override  

  67.         protected void onPostExecute(String  result) {  

  68.              progressBar.setVisibility(View.GONE);    //hide the progressBar  

  69.             if(result==null){  

  70.                 CallService.showNetErr(context);  

  71.                 return;  

  72.             }  

  73.             Toast.makeText(context,"result:"+result,Toast.LENGTH_SHORT).show();  

  74.             //here you can do anything you want after login   

  75.         }  

  76.     }  

  77. }  


我們在LoginActivity中初始化這個類的實例,傳入上下文以及ProgressBar(用於提高用戶體驗),再調用login方法傳入用戶名和 密碼這兩個參數。在進行操作前,onPreExecute方法顯示出ProgressBar,在返回結果後,onPostExecute方法再隱藏 ProgressBar。


然後我們再看doInBackGroud方法(這個方法聽名字就是異步操作啊):我們創建一個JsonObject對象,再使用鍵值對的方法 (類似map)傳入參數,最後轉成String後一起傳給服務器。在得到結果後把服務器返回的json形式的字符串轉成JsonObject。如果返回的 是空,說明連接有問題,就調用通用類的showNetErr方法。

我把Log截了圖,此前不清楚Json格式的朋友可以管中窺豹:




如果有需要傳一個list給服務器,還可以使用JsonArray類。比如:

[java] view plaincopy

  1. JSONArray jsonArray = new JSONArray();  

  2. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");  

  3. try {  

  4.     for (PeriodPO peroid : localPeriods) {      //這是一個我自定義的數據結構的list  

  5.         JSONObject periodObject = new JSONObject();  

  6.         periodObject.put("date", sdf.format(peroid.getDate()));  

  7.         periodObject.put("tag", peroid.getTag());  

  8.         periodObject.put("length", peroid.getLength());  

  9.         jsonArray.put(periodObject);            //把每一個對象轉成JsonObject,再把每個object放入Array  

  10.     }  

  11.     tosendsObject.put("periods", jsonArray);  

  12.     //add account info  

  13.     tosendsObject.put("username""test");  

  14. catch (JSONException e) {  

  15.     e.printStackTrace();  

  16. }  



=============寫在後面========================


我寫完之後,覺得傳參數這件事情也可以放在通用類中,但對如何把那部分代碼巧妙提取出來始終找不到非常好的方法。希望各位朋友可以多提建議,不吝賜教,多謝了!


ps:對文中代碼有不理解或者有意見的朋友也歡迎留言!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章