android菜鸟学习笔记25----与服务器端交互(二)解析服务端返回的json数据及使用一个开源组件请求服务端数据

补充:关于PHP服务端可能出现的问题:

如果你刚好也像我一样,用php实现的服务端程序,采用的是apache服务器,那么虚拟主机的配置可能会影响到android应用的调试!!

在android应用中访问的IP都是10.0.2.2,如果在apache虚拟主机配置文件中配置了多个虚拟主机,那么将默认解析为对第一个虚拟主机的请求,所以,在调试android应用时,应该将对应的服务端所配置的那个虚拟主机放在配置文件中的第一个虚拟主机的位置。否则就会出现请求的文件不存在等的错误。

服务端返回JSON数据及在android应用中解析JSON数据

1.新建一个json.php文件,返回json格式的数据

 1 <?php
 2
 3 if(isset($_REQUEST["username"])&& isset($_REQUEST["password"])){
 4
 5       $username = $_REQUEST["username"];
 6
 7       $password = $_REQUEST["password"];
 8
 9       if($username == "zhangsan" && $password == "123"){
10
11            $arr = array(
12
13                       "errorCode"=>200,
14
15                       "errorMsg"=>"login success"
16
17            );
18
19            echo json_encode($arr);
20
21       }else{
22
23            $arr = array(
24
25                       "errorCode"=>404,
26
27                       "errorMsg"=>"login failure"
28
29            );
30
31            echo json_encode($arr);
32
33       }
34
35 }else{
36
37       $arr = array(
38
39                       "errorCode"=>500,
40
41                       "errorMsg"=>"illeagle params"
42
43            );
44
45       echo json_encode($arr);
46
47 }
48
49 ?>

返回的信息格式如下:

{"errorCode":500,"errorMsg":"illeagle params"}

一个大括号内的表示的是一个json对象,内部存储的是键值对数据,键与值用冒号分隔,多个键值对之间用逗号分隔。

形式如同下面格式的是json array对象:

[{"errorCode":200,"errorMsg":"login success"},{"errorCode":200,"errorMsg":"login success"},{"errorCode":200,"errorMsg":"login success"}]

中括号里面存放的是用逗号分隔的一个个json对象。

2.Android中要解析json格式数据需要用到的类有JSONObject和JSONArray

JSONObject直接使用传入字符串形式的参数的构造方法创建JSONObject实例,然后调用相应的get方法,即可获取json形式数据中的每个键对应的值。

当返回的数据是用中括号括着的多个json形式字符串是,就要用到JSONArray了,同样可以使用字符串参数构造出JSONArray实例,然后可以使用下标的形式获取到其中的每一个JSONObject对象,然后使用JSONObject的方法分别取解析即可。

简单使用示例:

在MainActivity中添加上修改Handler的消息处理方法,当前通过get或者post取得的是json格式的数据,所以添加上对json数据的解析:

 1 private Handler handler = new Handler(){
 2
 3            public void handleMessage(android.os.Message msg) {
 4
 5                  if(msg.what == OK){
 6
 7                       String str = msg.obj.toString();
 8
 9                       try {
10
11                             JSONObject obj = new JSONObject(str);
12
13                             Log.i(TAG,obj.getString("errorCode"));
14
15                             Log.i(TAG,obj.getString("errorMsg"));
16
17                       } catch (JSONException e) {
18
19                             // TODO Auto-generated catch block
20
21                             e.printStackTrace();
22
23                       }
24
25
26
27                  }
28
29            }
30
31 };

运行结果:

有时候,服务端返回的可能是一些实体类信息,若用户登录成功,返回存放用户个人信息用以缓存在本地,这时,可能希望直接能将返回的JSON格式的数据解析为实体类对象,以简化操作。使用JSONObject类当然也能实现,只要获取到各个字段的值,然后通过它们构造实体类对象即可。但是,还有更简单的方式,那就是使用GSON。

3.使用GSON解析json数据

要在自己项目中使用GSON,有两种方式:

方式1:从网上下载gson的jar包,放到项目的libs目录中,然后添加到项目的build path中,就可以直接使用GSON了

方式2:下载GSON的源码,可以到github上下载,然后把源码整个复制到src目录下,之后也可以直接使用GSON了。

下面是GSON的简单使用示例,更多的使用可以参考GSON的帮助文档:在下载源码的包中有docs目录,里面就是GSON使用的帮助文档,可以在需要时参考。

新建一个实体类,存放返回的errorCode和errorMsg:

 1 package cn.csc.start.bean;
 2
 3
 4
 5 public class ResponseInfo {
 6
 7       private int errorCode;
 8
 9       private String errorMsg;
10
11       public int getErrorCode() {
12
13            return errorCode;
14
15       }
16
17       public void setErrorCode(int errorCode) {
18
19            this.errorCode = errorCode;
20
21       }
22
23       public String getErrorMsg() {
24
25            return errorMsg;
26
27       }
28
29       public void setErrorMsg(String errorMsg) {
30
31            this.errorMsg = errorMsg;
32
33       }
34
35       public ResponseInfo(int errorCode, String errorMsg) {
36
37            super();
38
39            this.errorCode = errorCode;
40
41            this.errorMsg = errorMsg;
42
43       }
44
45       public ResponseInfo() {
46
47            super();
48
49       }
50
51 }

修改Handler中消息处理中解析json数据的代码,这次改用GSON方式解析:

1 Gson gson = new Gson();
2
3 ResponseInfo info = gson.fromJson(str, ResponseInfo.class);
4
5 Toast.makeText(MainActivity.this, info.getErrorCode()+info.getErrorMsg(), Toast.LENGTH_LONG).show();

注意到,使用GSON的方式解析到实体类对象非常简单:

没有特别的需求时,使用默认构造创建GSON实例即可,需要特殊的配置时,可以使用GsonBuilder来创建GSON实例,具体参考说明文档

调用fromJson()传入要解析的数据,及解析后的对象类型,即可完成从json格式字符串到实体类对象的解析。

若是json array形式的字符串,解析则稍微麻烦一点:

如:想要解析[{"errorCode":200,"errorMsg":"login success"},{"errorCode":200,"errorMsg":"login success"},{"errorCode":200,"errorMsg":"login success"}]为List<ResponseInfo>

但是不能List<ResponseInfo>.class,这时GSON中提供了获取泛型的类型信息的方法:

使用TypeToken

TypeToken< List<ResponseInfo>> list = new TypeToken< List<ResponseInfo>>() {};

然后调用list.getType()注意返回的是Type类型的对象,而Gson的fromJson()方法刚好有第二个参数为Type类型的重载形式。

所以,对[{"errorCode":200,"errorMsg":"login success"},{"errorCode":200,"errorMsg":"login success"},{"errorCode":200,"errorMsg":"login success"}]解析的具体代码如下:

1 Gson gson = new Gson();
2
3 TypeToken<List<ResponseInfo>> list = new TypeToken<List<ResponseInfo>>(){};
4
5 List<ResponseInfo> info_list = gson.fromJson(str, list.getType());

以上,就是两种对json形式数据的解析方式。

与服务器交互的方式除了内置的HttpURLConnection和HttpClient之外,还可以选择一些优秀的开源项目,来简化与服务端交互的工作,如使用AsyncHttpClient

AsyncHttpClient可以到github上获取:

在github中搜说async-http即可找到该项目,然后clone或者下载zip包就可以获得该项目了。

在自己的项目中使用async-http的方式如同GSON,也可以直接使用源码,或者引用jar包,根据个人喜好即可。

简单演示下async-http发送get和post请求的示例:

在MainActivity中添加两个方法:

使用AsyncHttpClient发送get请求

 1 private void async_get_test(){
 2
 3            String username = et_username.getText().toString();
 4
 5            String password = et_password.getText().toString();
 6
 7            AsyncHttpClient client = new AsyncHttpClient();
 8
 9            client.get("http://10.0.2.2/index.php?username="+username+"&password="+password, new AsyncHttpResponseHandler() {
10
11
12
13                  @Override
14
15                  public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
16
17                       // TODO Auto-generated method stub
18
19                       Message msg = new Message();
20
21                       msg.what = OK;
22
23                       msg.obj = new String(responseBody);
24
25                       handler.sendMessage(msg);
26
27                  }
28
29
30
31                  @Override
32
33                  public void onFailure(int statusCode, Header[] headers,
34
35                             byte[] responseBody, Throwable error) {
36
37                       // TODO Auto-generated method stub
38
39                       Message msg = new Message();
40
41                       msg.what = OK;
42
43                       msg.obj = new String(responseBody);
44
45                       handler.sendMessage(msg);
46
47                  }
48
49            });
50
51       }

使用AsyncHttpClient发送post请求

 1 private void async_post_test(){
 2
 3            String username = et_username.getText().toString();
 4
 5            String password = et_password.getText().toString();
 6
 7            AsyncHttpClient client = new AsyncHttpClient();
 8
 9            RequestParams params = new RequestParams();
10
11            params.add("username", username);
12
13            params.add("password", password);
14
15            client.post("http://10.0.2.2/index.php", params , new AsyncHttpResponseHandler() {
16
17
18
19                  @Override
20
21                  public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
22
23                       // TODO Auto-generated method stub
24
25                       Message msg = new Message();
26
27                       msg.what = OK;
28
29                       msg.obj = new String(responseBody);
30
31                       handler.sendMessage(msg);
32
33                  }
34
35
36
37                  @Override
38
39                  public void onFailure(int statusCode, Header[] headers,
40
41                             byte[] responseBody, Throwable error) {
42
43                       // TODO Auto-generated method stub
44
45                       Message msg = new Message();
46
47                       msg.what = OK;
48
49                       msg.obj = new String(responseBody);
50
51                       handler.sendMessage(msg);
52
53                  }
54
55            });
56
57 }

可以看到使用AsyncHttpClient的方式非常简单:

get方式:

创建AsyncHttpClient对象,然后调用get方法即可。

唯一稍微复杂的就是get方法的第二个参数:AsyncHttpResponseHandler,需要创建一个匿名内部类对象,然后重写AsyncHttpResponseHandler的两个方法,分别是网络请求成功的回调方法及网络请求失败的回调方法。

post方式:

就比get方式多了一个传递参数而已:

RequestParams params = new RequestParams();

params.add("username", username);

params.add("password", password);

使用RequestParams对象存放要提交的参数,然后将其传递给post()方法即可。

时间: 07-12

android菜鸟学习笔记25----与服务器端交互(二)解析服务端返回的json数据及使用一个开源组件请求服务端数据的相关文章

android菜鸟学习笔记24----与服务器端交互(一)使用HttpURLConnection和HttpClient请求服务端数据

主要是基于HTTP协议与服务端进行交互. 涉及到的类和接口有:URL.HttpURLConnection.HttpClient等 URL: 使用一个String类型的url构造一个URL对象,如: URL url = new URL(http://10.0.2.2/index.php); openConnection()方法返回一个对指定url的资源的连接.返回类型是URLConnection,但是,由于这里我们一般用的是http协议,所以返回的实际是HttpURLConnection对象,故一

android菜鸟学习笔记12----Android控件(一) 几个常用的简单控件

主要参考<第一行代码> 1.TextView: 功能与传统的桌面应用开发中的Label控件相似,用于显示文本信息 如: 1 <TextView 2 3 android:layout_width="wrap_content" 4 5 android:layout_height="wrap_content" 6 7 android:textColor="#0000ff" 8 9 android:textSize="40sp

android菜鸟学习笔记27----Fragment的简单使用

1.Fragment的生命周期: 简单在新建一个MyFragment继承自Fragment,重写各个生命周期回调方法,各个方法中直接输出标识相关函数被调用的信息. 重写MainActivity的各个生命周期回调方法,同样输出标识信息. MyFragment.java: 1 public class MyFragment extends Fragment { 2 3 @Override 4 5 public void onActivityCreated(Bundle savedInstanceSt

android菜鸟学习笔记7----android布局(二)

3.FrameLayout:帧布局 如同Flash或者photoshop中图层的概念,在上面的图层遮盖下面的图层,没被遮到的地方仍然显示出来. 右击res/layout,然后在弹出的菜单中选择new,然后选择Android Xml File,要新建FrameLayout布局文件,就选择FrameLayout作为其根节点即可.文件名为frame_layout.xml. 代码如下: 1 <?xml version="1.0" encoding="utf-8"?&g

android菜鸟学习笔记6----android布局(一)

Android应用的UI组件都是继承自View类,View类表示的就是一个空白的矩形区域.常用的组件如TextView.Button.EditText等都直接或间接继承自View. 此外,View还有一个重要的子类ViewGroup,该类可以用来包含多个View组件,本身也可以当做一个View组件被其他的ViewGroup所包含,由此,可以构建出非常复杂的UI界面. 常用的布局管理器如FrameLayout.LinearLayout.RelativeLayout等都直接继承自ViewGroup.

android菜鸟学习笔记28----Android中的Service生命周期及本地和远程服务绑定的实现

Service是Android中长期在后台运行的没有界面的组件,使用服务的优势在于:能够提高进程的优先级,系统不容易回收掉进程,即便回收了,内存充足的时候,会把进程重新创建. 1.服务的简单使用示例: 1.1.定义一个服务: 定义一个服务的方式是定义一个类继承自Service: 1 public class MyService extends Service { 2 3 @Override 4 5 public IBinder onBind(Intent intent) { 6 7 // TOD

android菜鸟学习笔记29----Android应用向用户发送提示信息的方式总结

常见的向用户发送提示信息的方式有3种,分别为: 1)发送Toast信息 2)弹出对话框 3)发送通知 总结如下: 方式1:发送Toast信息: 这种方式最简单,在之前的学习中多次使用过.Toast是在一个浮动于应用之上的View中显示信息,显示一定的时间间隔后自动消失,不可获得焦点. 最简单的用法就是之前的学习中一直使用的:通过一个静态的makeText()方法返回一个Toast对象,然后调用show()方法. 如: 布局文件添加一个Button: 1 <Button 2 3 android:i

Android:日常学习笔记(6)——探究活动(3)

Android:日常学习笔记(6)--探究活动(3) 活动的生命周期 返回栈 Android中的活动是可以叠加的,我们每启动一个新活动,就会覆盖在原来的活动上,点击Back以后销毁最上面的活动,下面的活动就会重新显现出来.Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合. 默认情况下,每当我们启动一个新的活动,他会在返回栈中入栈,并处于栈顶位置.而每当我们按下Back或者Finish以后,处于栈顶位置的活动会出栈. 活动的状态 运行状态(栈顶的元素).暂停

java/android 设计模式学习笔记(6)---适配器模式

这篇来介绍一下适配器模式(Adapter Pattern),适配器模式在开发中使用的频率也是很高的,像 ListView 和 RecyclerView 的 Adapter 等都是使用的适配器模式.在我们的实际生活中也有很多类似于适配器的例子,比如香港的插座和大陆的插座就是两种格式的,为了能够成功适配,一般会在中间加上一个电源适配器,形如: 这样就能够将原来不符合的现有系统和目标系统通过适配器成功连接. 说到底,适配器模式是将原来不兼容的两个类融合在一起,它有点类似于粘合剂,将不同的东西通过一种转