Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 輕松實現網絡交互模板

Android 輕松實現網絡交互模板

編輯:關於Android編程

看完本文,您可以學到:


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

 

2.JSON的使用

3.檢查網絡連接

4.AsyncTask的使用

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

 

\

\

 

 

 

一、通用類的編寫


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

    /**
     * check net connection before call
     *
     * @param context
     * @return
     */
    private static boolean checkNet(Context context) {
        ConnectivityManager connectivity = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity != null) {
            // 獲取網絡連接管理的對象
            NetworkInfo info = connectivity.getActiveNetworkInfo();
            if (info != null && info.isConnected()) {
                // 判斷當前網絡是否已經連接
                if (info.getState() == NetworkInfo.State.CONNECTED) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * call service by net
     *
     * @param urlString url
     * @param content   a string of json,params
     * @return the result,a string of json
     */
    public static String call(String urlString, String content, Context context) {
        if (!checkNet(context)) {
            return null;
        }
        try {
            URL url = new URL(urlString);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("User-Agent", "Fiddler");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Charset", "utf-8");
            OutputStream os = conn.getOutputStream();
            os.write(content.getBytes());
            os.close();
            int code = conn.getResponseCode();
            if (code == 200) {
                BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
                String retData;
                String responseData = "";
                while ((retData = in.readLine()) != null) {
                    responseData += retData;
                }
                in.close();
                return responseData;
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void showNetErr(Context context){
        new AlertDialog.Builder(context)
                .setTitle("網絡錯誤")
                .setMessage("網絡連接失敗,請確認網絡連接")
                .setPositiveButton("確定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface arg0, int arg1) {

                    }
                }).show();
    }
    
}

其中,判斷網絡連接狀態是借助Android系統提供的ConnectivityManager的方法實現的,借助這個類我們還可以獲取更多的連接狀態信息,包括當前是用流量還是WIFI等等。
然後,在調用本類核心方法call()時,傳入了三個參數,一個是後台服務的url路徑,一個是已經組裝好的參數,第三個是上下文context。 在這個方法中,我們先去判斷網絡連接,未連接就直接返回空。否則就使用HttpURLConnection方法向服務器發送請求,再把服務器的返回值返回給調用者。
另一個showNetErr方法就只是簡單地跳出一個對話框進行提示。

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


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

public class Login {

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

    private ProgressBar progressBar;
    private Context context;

    private String userName;
    private String password;

    public Login( Context context,ProgressBar progressBar) {
        this.progressBar=progressBar;
        this.context = context;
    }

    public void login(String userName,String password) {
        Log.i(TAG, "call login");
        this.userName=userName;
        this.password=password;
        new LoginTask().execute();
    }

    class LoginTask extends AsyncTask {
        @Override
        protected String doInBackground(Void... params) {
            JSONObject tosendsObject = new JSONObject();
            Log.i(TAG, "start put json!");
            try {
                //add account info
                tosendsObject.put("username", userName);
                tosendsObject.put("password", password);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            //change json to String
            String content = String.valueOf(tosendsObject);
            Log.i(TAG, "send :" + content);
            String responseData = CallService.call(urlString, content,context);
            if(responseData==null || responseData.equals("")){
                return null;
            }
            Log.i(TAG, "res:" + responseData);
            JSONObject resultObject = null;
            String result=null;
            try {
                resultObject = new JSONObject(responseData);
                result = resultObject.getString("result");
                Log.i(TAG, "result:" + result);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return result;
        }

        @Override
        protected void onPreExecute() {
            progressBar.setVisibility(View.VISIBLE);    //show the progressBar
            super.onPreExecute();
        }

        @Override
        protected void onPostExecute(String  result) {
             progressBar.setVisibility(View.GONE);    //hide the progressBar
            if(result==null){
                CallService.showNetErr(context);
                return;
            }
            Toast.makeText(context,"result:"+result,Toast.LENGTH_SHORT).show();
            //here you can do anything you want after login 
        }
    }
}

我們在LoginActivity中初始化這個類的實例,傳入上下文以及ProgressBar(用於提高用戶體驗),再調用login方法傳入用戶名和密碼這兩個參數。在進行操作前,onPreExecute方法顯示出ProgressBar,在返回結果後,onPostExecute方法再隱藏ProgressBar。
然後我們再看doInBackGroud方法(這個方法聽名字就是異步操作啊):我們創建一個JsonObject對象,再使用鍵值對的方法(類似map)傳入參數,最後轉成String後一起傳給服務器。在得到結果後把服務器返回的json形式的字符串轉成JsonObject。如果返回的是空,說明連接有問題,就調用通用類的showNetErr方法。 我把Log截了圖,此前不清楚Json格式的朋友可以管中窺豹:
\

如果有需要傳一個list給服務器,還可以使用JsonArray類。比如:
            JSONArray jsonArray = new JSONArray();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            try {
                for (PeriodPO peroid : localPeriods) {      //這是一個我自定義的數據結構的list
                    JSONObject periodObject = new JSONObject();
                    periodObject.put("date", sdf.format(peroid.getDate()));
                    periodObject.put("tag", peroid.getTag());
                    periodObject.put("length", peroid.getLength());
                    jsonArray.put(periodObject);            //把每一個對象轉成JsonObject,再把每個object放入Array
                }
                tosendsObject.put("periods", jsonArray);
                //add account info
                tosendsObject.put("username", "test");
            } catch (JSONException e) {
                e.printStackTrace();
            }


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

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved