最近做项目要求使用到网络,想来想去选择了AsyncHttpClient框架开进行APP开发。在这里把我工作期间遇到的问题以及对AsyncHttpClient的使用经验做出相应总结,希望能对您的学习有所帮助。
首先按照惯例先来简单了解一些AsyncHttpClient网络框架的一些知识。
1、简介
Android中网络请求一般使用Apache HTTP Client或者采用HttpURLConnect,但是直接使用这两个类库需要写大量的代码才能完成网络post和get请求,而使用android-async-http这个库可以大大的简化操作,它是基于Apache’s HttpClient ,所有的请求都是独立在UI主线程之外,通过回调方法处理请求结果,采用android Handler message 机制传递信息。
2、特性
(1)采用异步http请求,并通过匿名内部类处理回掉结果
(2)http请求独立在UI主线程之外
(3)采用线程池来处理并发请求
(4)采用RequestParams类创建GET/POST参数
(5)不需要第三方包即可支持Multipart file文件上传
(6)大小只有25kb
(7)自动为各种移动电话处理连接断开时请求重连
(8)超快的自动gzip响应解码支持
(9)使用BinaryHttpResponseHandler类下载二进制文件(如图片)
(10)使用JsonHttpResponseHandler类可以自动将响应结果解析为json格式(下面会重点讲解JsonHttpResponseHandler在使用过程中存在的问题)
(11)持久化cookie存储,可以将cookie保存到你的应用程序的SharedPreferences中
以上的理论源于网友的博客,有兴趣的朋友如果想了解更多的关于AsyncHttpClient的理论知识可以去参考一下这位网友的博客
《Android网络请求框架AsyncHttpClient详解》:http://blog.csdn.net/xiaohui2015/article/details/51462782
3、使用办法
在讲解实例之前,请先看接口文档,结合接口文档和实例学习起来更清晰。
用户登录接口文档:
接口地址:http://xxx.xxx.xxx/MobileService/userLogin
备注:
请求参数:
{
username:”用户登录”,
password:”密码”
}
返回结果:
{
“code”:”状态码”,1000 返回成功 其他失败
“message”:”提示信息”,
“data”:{
userid:”用户id”,
supplier:”供应商id”,
suppliername:”供应商名称”
}
}
usercount = (EditText) findViewById(R.id.usernumber); password = (EditText) findViewById(R.id.password);
下面代码中的usercount和password是我在界面中定义的两个EditText类型的控件。用来输入用户的账号和密码。
AsyncHttpClient client = new AsyncHttpClient(); String url = "http://xxx.xxx.xxx/MobileService/userLogin"; // 使用RequestParams来向接口发送请求的参数,结合接口文档可以看出我要向服务器发送的参数为username和password RequestParams params = new RequestParams(); params.put("username", usercount.getText().toString()); params.put("password", password.getText().toString()); // 请注意,在这里我是用的是AsyncHttpResponseHandler来进行网络处理,而没有使用JsonHttpResponseHandler来进行处理,原因在下面讲明。 //另外需要注意的是这里一定要用post方式提交,而且在client.的时候千万不要忘记选择带参数params的post,否则你拿什么和服务器交流?我就翻过这样的错误。 client.post(url, params, new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { // TODO Auto-generated method stub try { // 从服务器中接收返回的数据,并进行字符集设置,返回的结果集放resultDate中,resultDate相当于一个容器,所有的返回信息都在其中。只要用过JSON解析出来返回值并逐个获取返回值就OK了。 // 在不要问我为什么这么使用,我也不知道。只清楚这么好用。 String resultDate = new String(arg2, "utf-8"); // 结合接口文档可以看出返回的结果都是单个的,没有返回的是集合或数组这样多个的情况,所以直接用JSONObject来接受返回值即可 JSONObject js = new JSONObject(resultDate); // 将code、message、data解析出来。对于返回值是单个的而不是集合或数组的取值方式有两种。1:js.getJSONObject("xxx");2:js.getString("xxx");xxx代表任意String类型的字符串 //通过接口文档可以看出,返回值都是String类型的数据,所以我在这里选择了第二种取值方式,如果使用第一种会造成类型不匹配而导致程序错误。 String code = js.getString("code"); String message = js.getString("message"); String data = js.getString("data"); //对data中的数据进行进一步的解析,原理同上面一样 JSONObject jsonObject = new JSONObject(data); String userid = jsonObject.getString("userid"); String supplier = jsonObject.getString("supplier"); String suppliername = jsonObject.getString("suppliername"); //1000代表状态码,表示登陆成功 if ("1000".equals(code)) { //使用SharedPreferences将用户的账户和密码存储起来,关于SharedPreferences的存储知识请参考我的另外一篇文章 SharedPreferences sharedPreferences = getSharedPreferences( message, Activity.MODE_PRIVATE); Editor editor = sharedPreferences.edit(); editor.putString("username", usercount.getText() .toString()); editor.putString("password", password.getText() .toString()); editor.commit(); Intent intent = new Intent(getApplicationContext(), MainActivity.class); intent.putExtra("userid", userid.toString()); startActivity(intent); } else { Toast.makeText(getApplicationContext(), "账号或密码错误", Toast.LENGTH_LONG).show(); } } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { // TODO Auto-generated method stub Toast.makeText(getApplicationContext(), "请检查网络!", Toast.LENGTH_SHORT).show(); } });
上面的代码是通过AsyncHttpResponseHandler()来处理服务器的返回值的,AsyncHttpClient中还有一个用来处理服务器的返回值,我看大多数博客都写的是这个JsonHttpResponseHandler()。
JsonHttpResponseHandler()来处理服务器返回值的代码如下:
AsyncHttpClient client = new AsyncHttpClient(); String url = "http://xxx.xxx.xxx/MobileService/userLogin"; RequestParams params = new RequestParams(); params.put("username", usercount.getText().toString()); params.put("password", password.getText().toString()); client.post(url, params, new JsonHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { // TODO Auto-generated method stub super.onSuccess(statusCode, headers, response); try { JSONObject js = new JSONObject(response.toString()); String code = js.getString("code"); String message = js.getString("message"); String data = js.getString("data"); JSONObject jsonObject = new JSONObject(data); String userid = jsonObject.getString("userid"); String supplier = jsonObject.getString("supplier"); String suppliername = jsonObject.getString("suppliername"); if ("1000".equals(code)) { SharedPreferences sharedPreferences = getSharedPreferences( message, Activity.MODE_PRIVATE); Editor editor = sharedPreferences.edit(); editor.putString("username", usercount.getText() .toString()); editor.putString("password", password.getText() .toString()); editor.commit(); Intent intent = new Intent(getApplicationContext(), MainActivity.class); intent.putExtra("userid", userid.toString()); startActivity(intent); } else { Toast.makeText(getApplicationContext(), "账号或密码错误", Toast.LENGTH_LONG).show(); } } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONArray errorResponse) { // TODO Auto-generated method stub super.onFailure(statusCode, headers, throwable, errorResponse); Toast.makeText(getApplicationContext(), "请检查网络!", Toast.LENGTH_SHORT).show(); } });
请看第6行和第9行代码,第6行代码就是使用JsonHttpResponseHandler()来处理传回的数据的。第9行代码中的参数response就是上面特性中的第10条:使用JsonHttpResponseHandler类可以自动将响应结果解析为json格式。使用JsonHttpResponseHandler()虽然很方便,但是却存在着很大的问题。JsonHttpResponseHandler()在使用过程中有时莫名的出现请求不了服务器的情况,就是onSuccess和onFailure方法都进不去,这样就直接造成了程序无法正常使用。如果你不信你可以试试,明明前几分钟你使用JsonHttpResponseHandler()处理返回数据还好用呢,而你在这期间根本没有动过其中的代码,JsonHttpResponseHandler就莫名其妙的不好用了,而且原因不知道,无论你怎么调试都不成功。相反AsyncHttpResponseHandler()则根本不存在这样的问题。所以我就果断的放弃使用JsonHttpResponseHandler(),而采用AsyncHttpResponseHandler()来处理返回数据。当然AsyncHttpClient当中还封装了不少别的用来处理响应的方法,因为别的本人没有使用过,具体怎么样我也不知道。如果有使用过别的方法的朋友可以在下面留言告诉我,我们好相互学习。
对于接口返回值是数组或集合的形式有不会的朋友可以参照下面的代码,我就不解释了,反正是照着代码直接写肯定没有问题。
AsyncHttpClient client = new AsyncHttpClient(); String url = "http://xxx.xxx.xxx/MobileService/userLogin"; RequestParams params = new RequestParams(); params.add("userid", userid); client.post(url, params, new AsyncHttpResponseHandler() { @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { // TODO Auto-generated method stub try { String resultDate = new String(arg2, "utf-8"); JSONObject js1 = new JSONObject(resultDate); String code = js1.getString("code"); String message = js1.getString("message"); String data = js1.getString("data"); JSONObject js2 = new JSONObject(data); if ("1000".equals(code)) { String productlist = js2.getString("productlist"); JSONArray array = new JSONArray(productlist);//productlist返回的数据就是一个集合 //List<Map<String, Object>> arrays,这个在全局变量中进行声明。 arrays = new ArrayList<Map<String, Object>>(); for (int i = 0; i < array.length(); i++) { JSONObject js3 = array.getJSONObject(i); String batchnumber = js3.getString("batchnumber"); HashMap<String, Object> map = new HashMap<String, Object>(); map.put("batchnumber", batchnumber); arrays.add(map); } System.out.println("arrays:" + arrays); } } catch (UnsupportedEncodingException e) { Log.e("log_tag", "Error parsing classname data" + e.toString()); } catch (JSONException e) { // TODO Auto-generated catch block Log.e("log_tag", "Request failed" + e.toString()); } } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { // TODO Auto-generated method stub Toast.makeText(getApplicationContext(), "服务异常", Toast.LENGTH_SHORT).show(); } });
关于AsyncHttpClient网络框架的使用我的了解就是这么多了,关于JsonHttpResponseHandler()有时候不好用的问题如果谁知道怎么回事欢迎留言告诉我,鄙人感激不尽。希望这篇博客对大家有所帮助。