看完本文,您可以学到:


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<Void, Void, String> {        @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();            }


=============写在后面========================
我写完之后,觉得传参数这件事情也可以放在通用类中,但对如何把那部分代码巧妙提取出来始终找不到非常好的方法。希望各位朋友可以多提建议,不吝赐教,多谢了!
ps:对文中代码有不理解或者有意见的朋友也欢迎留言!

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. [置顶] android 程序开发的插件化 模块化方法 之二
  3. [置顶] Android(安卓)自定义ViewGroup实现整个Item布局竖直跑马
  4. Android(安卓)bugs——RecyclerView scrollToPosition不会触发sc
  5. Android坐标系统常用方法属性总结
  6. Android(安卓)ROM分析(1):刷机原理及方法
  7. 【原创】Android(安卓)判断默认数据网络是否为开,若关则跳转到网
  8. android 游戏:俄罗斯方块的小结
  9. BigInteger类的使用方法

随机推荐

  1. Android断点续传核心代码
  2. Android下使用配置文件(Preferences)
  3. android调用系统联系人列表
  4. Android:onNewIntent()触发机制及注意事项
  5. Android(安卓)Studio 3.0新建项目AAPT2
  6. ImageSpan的使用
  7. Android(安卓)HttpClient
  8. android 获取 图片 缩略图
  9. Android(安卓)Studio 安卓模拟器安装本地
  10. Android(安卓)gallery实现二级联动效果