原文:Xamarin.Android开发实践(四)

Xamarin.Android下获取与解析JSON

一、新建项目

1.新建一个Android项目,并命名为为NetJsonList

2.右击引用,选择添加引用,引用System.Json.dll

二、同步请求

既然是跨平台,我们自然不能按照java下的方式进行编写,否则如何跨平台呢,所以我们需要使用Syste.Net命名空间下的两个类:HttpWebRequestHttpWebResponse

首先打开Resources/layout/Main.axml文件

删除其他上面的控件,并拖拽一个Text(large)到其中。

接着打开MainActivity.cs文件,并将如下代码写入其中

 1 namespace NetJsonList
2 {
3 [Activity(Label = "NetJsonList", MainLauncher = true, Icon = "@drawable/icon")]
4 public class MainActivity : Activity
5 {
6 TextView tv;
7
8 protected override void OnCreate(Bundle bundle)
9 {
10 base.OnCreate(bundle);
11 SetContentView(Resource.Layout.Main);
12
13 tv = FindViewById<TextView>(Resource.Id.textView1);
14
15 LoadXamarin();
16 }
17
18 public void LoadXamarin()
19 {
20 //测试用
21 string url = "http://www.xamarin-cn.com/test.json";
22
23 //创建一个请求
24 var httpReq = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
25
26 //获取响应
27 var httpRes = (HttpWebResponse)httpReq.GetResponse();
28
29 //读取响应的字符串
30 String text = new StreamReader(httpRes.GetResponseStream()).ReadToEnd();
31 tv.Text = text;
32 }
33 }
34 }

这里我们通过HttpWebRequestCreate静态方法创建了一个请求,那么下面我们可以获取响应了,笔者这里直接使用StreamReader读取了,以便显示出来。

注:如果要在在短时间内高频率的使用HTTP请改用HttpURLConnection。

最终显示的结果如下所示:

但是我们在编码的过程中绝对不能这么做,因为这样会使UI线程阻塞。意思就是用户使用这个app时会出现卡顿,这样对于任何一个人使用者来说都是很难忍受的,所以下面我们要采用异步的方式来实现。

三、异步请求

首先我们先把异步请求回调的方法写出来:

 1         //异步回调方法
2 public void ReadXamarin(IAsyncResult asyn)
3 {
4 var httpReq = (HttpWebRequest)asyn.AsyncState;
5
6 //获取响应
7 using (var httpRes = (HttpWebResponse)httpReq.EndGetResponse(asyn))
8 {
9 //判断是否成功获取响应
10 if (httpRes.StatusCode == HttpStatusCode.OK)
11 {
12 //读取响应
13 var text = new StreamReader(httpRes.GetResponseStream()).ReadToEnd();
14
15 //切换到UI线程,否则无法对控件进行操作
16 RunOnUiThread(() =>
17 {
18 tv.Text = text;
19 });
20 }
21 }
22 }
 

通过AsyncState获取HttpWebRequest的引用,然后再调用其EndGetResponse方法获取响应,并将响应的字符串显示,特别需要注意的是我们这里使用了RunOnUiThread方法,因为异步回调的方法不是使用UI线程执行的,这也是为什么这样做就不会阻塞UI线程了。

当然有了异步操作的回调方法,自然在调用的时候需要使用特殊的方法:

1         public void LoadXamarin()
2 {
3 //测试用
4 string url = "http://www.xamarin-cn.com/test.json";
5
6 //创建一个请求
7 var httpReq = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
8 httpReq.BeginGetResponse(new AsyncCallback(ReadXamarin), httpReq);
9 }
 

所有的代码如下所示:

 1 namespace NetJsonList
2 {
3 [Activity(Label = "NetJsonList", MainLauncher = true, Icon = "@drawable/icon")]
4 public class MainActivity : Activity
5 {
6 TextView tv;
7
8 protected override void OnCreate(Bundle bundle)
9 {
10 base.OnCreate(bundle);
11 SetContentView(Resource.Layout.Main);
12
13 tv = FindViewById<TextView>(Resource.Id.textView1);
14
15 LoadXamarin();
16 }
17
18 public void LoadXamarin()
19 {
20 //测试用
21 string url = "http://www.xamarin-cn.com/test.json";
22
23 //创建一个请求
24 var httpReq = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
25 httpReq.BeginGetResponse(new AsyncCallback(ReadXamarin), httpReq);
26 }
27
28 //异步回调方法
29 public void ReadXamarin(IAsyncResult asyn)
30 {
31 var httpReq = (HttpWebRequest)asyn.AsyncState;
32
33 //获取响应
34 using (var httpRes = (HttpWebResponse)httpReq.EndGetResponse(asyn))
35 {
36 //判断是否成功获取响应
37 if (httpRes.StatusCode == HttpStatusCode.OK)
38 {
39 //读取响应
40 var text = new StreamReader(httpRes.GetResponseStream()).ReadToEnd();
41
42 //切换到UI线程,否则无法对控件进行操作
43 RunOnUiThread(() =>
44 {
45 tv.Text = text;
46 });
47 }
48 }
49 }
50 }
51 }
 

四、利用await的异步请求

通过c# 5.0 的新特性await我们可以写更少的代码实现异步,我们修改LoadXamarin方法:

 1         public async void LoadXamarin()
2 {
3 //测试用
4 string url = "http://www.xamarin-cn.com/test.json";
5
6 //创建一个请求
7 var httpReq = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
8 var httpRes = (HttpWebResponse)await httpReq.GetResponseAsync();
9 if (httpRes.StatusCode == HttpStatusCode.OK)
10 {
11 var text = new StreamReader(httpRes.GetResponseStream()).ReadToEnd();
12 tv.Text = text;
13 }
14 }
 

可以看到我们给这个方法加了一个async关键字,如果不加这个关键字,在该方法中是无法使用await的,下面我们就看到了这句代码:

1 var httpRes = (HttpWebResponse)await httpReq.GetResponseAsync();

当Ui线程执行到这句后,直接就会跳过去,不会等待。当然下面的方法也不会去执行了,只有当这个方法返回了结果之后,UI线程才会回到这句代码,并继续执行下面的方法。当然这些只是障眼法,其实c#已经把下面的代码作为了异步回调执行的方法了:

1             if (httpRes.StatusCode == HttpStatusCode.OK)
2 {
3 var text = new StreamReader(httpRes.GetResponseStream()).ReadToEnd();
4 tv.Text = text;
5 }

并且执行的线程依然是之前执行该方法的线程,如果你创建一个新的线程去执行。那么就必须使用RunOnUiThread方法了。还有一个缺点就是不能在其中进行复杂的运算,否则还是会造成UI线程的阻塞。

五、解析JSON

在开始本节前,必须确保引用了正确的System.Json类库,否则无法使用。

首先我们先看看json数据的格式:

1 {
2 "T": [
3 "T1",
4 "T2",
5 "T3",
6 "T4"
7 ]
8 }

知道了json数据格式了,我们还要理解下System.Json中有哪些类:

JsonValue:是基础类,代表一个Json值

JsonObject:继承JsonValue,代表一个Json对象

JsonArray:继承JsonValue,代表一个Json数组

JsonPrimitive:继承JsonValue,组织Json数据时用

JsonType:枚举,区分是什么类型

而我们今天只需要使用到JsonObjectJsonArray,首先是JsonObject代表整个Json对象,我们可以通过它的静态方法Load直接读取流,比如下面的方式:

1 var text = JsonObject.Load(httpRes.GetResponseStream());

但是Load返回的是JsonValue,但是大多数情况都是代表一个Json对象,所以我们需要将它强制转换成JsonObject类型,这样我们就可以读取其中的T了:

1                 var text = (JsonObject)JsonObject.Load(httpRes.GetResponseStream());
2 var array = (JsonArray)text["T"];

当然我们还需要使用Linq读取这个数组(注意要using System.Linq命名空间

1                 var text = (JsonObject)JsonObject.Load(httpRes.GetResponseStream());
2 var result = (from item in (JsonArray)text["T"]
3 select item.ToString()).ToArray();

这样我们获取了一个字符串组了,result类型为string[]。为了显示这个数组,我们需要将当前的活动继承自ListActivity:

然后将代码修改成如下所示:

 1 namespace NetJsonList
2 {
3 [Activity(Label = "NetJsonList", MainLauncher = true, Icon = "@drawable/icon")]
4 public class MainActivity : ListActivity
5 {
6 protected override void OnCreate(Bundle bundle)
7 {
8 base.OnCreate(bundle);
9 LoadXamarin();
10 }
11
12 public async void LoadXamarin()
13 {
14 //测试用
15 string url = "http://www.xamarin-cn.com/test.json";
16
17 //创建一个请求
18 var httpReq = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
19 var httpRes = (HttpWebResponse)await httpReq.GetResponseAsync();
20 if (httpRes.StatusCode == HttpStatusCode.OK)
21 {
22 var text = (JsonObject)JsonObject.Load(httpRes.GetResponseStream());
23 var result = (from item in (JsonArray)text["T"]
24 select item.ToString()).ToArray();
25 ListAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, result);
26 }
27 }
28 }
29 }

六、解决翻转后重复执行

做到这步的可以在LoadXamarin中下一个断点,当你点击模拟器并按下Ctrl+F12翻转后你会发现LoadXamarin又重新执行了一次。这样就带来了一个问题,有时候我们仅仅只需要第一次获取即可,该翻转则会导致重复执行,那么就会浪费用户的流量同时也会浪费资源,所以我们这里就需要能够将这种状态维持,这里我们就需要重写OnRetainNonConfigurationInstance事件,当然该方法需要返回一个Java.Lang.Object类型的返回值,而这个返回值就是我们需要保存的状态,当然这个状态不会存在于OnCreate的bundle中,还是有一个专门的属性LastNonConfigurationInstance,这样我们可以将上面的代码改写成如下:

 1 namespace NetJsonList
2 {
3 [Activity(Label = "NetJsonList", MainLauncher = true, Icon = "@drawable/icon")]
4 public class MainActivity : ListActivity
5 {
6 class Test : Java.Lang.Object
7 {
8 public string[] Results { get; set; }
9 }
10
11 Test t;
12
13 protected override void OnCreate(Bundle bundle)
14 {
15 base.OnCreate(bundle);
16 LoadXamarin();
17 }
18
19 //重写该方法
20 public override Java.Lang.Object OnRetainNonConfigurationInstance()
21 {
22 return t;
23 }
24
25 public async void LoadXamarin()
26 {
27 t = LastNonConfigurationInstance as Test;
28 //判断是否存在之前的状态
29 if (t != null)
30 {
31 ListAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, t.Results);
32 }
33 else
34 {
35
36 //测试用
37 string url = "http://www.xamarin-cn.com/test.json";
38
39 //创建一个请求
40 var httpReq = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
41 var httpRes = (HttpWebResponse)await httpReq.GetResponseAsync();
42 if (httpRes.StatusCode == HttpStatusCode.OK)
43 {
44 var text = (JsonObject)JsonObject.Load(httpRes.GetResponseStream());
45 var result = (from item in (JsonArray)text["T"]
46 select item.ToString()).ToArray();
47 t = new Test()
48 {
49 Results = result
50 };
51 ListAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, result);
52 }
53 }
54 }
55 }
56 }

七、小结

通过上面的学习我们仅仅掌握了在跨平台下最基础的网络访问以及Json数据解析的方法,还有在活动如何保存当前的状态。

Xamarin.Android开发实践(四)的更多相关文章

  1. Xamarin.Android开发实践(五)

    原文:Xamarin.Android开发实践(五) 一.服务的生命周期 服务与活动一样,在它的整个生命周期中存在着一些事件,下图可以很好解释整个过程以及涉及到的方法: 在真实的使用中,Service来 ...

  2. Xamarin.Android开发实践(二)

    原文:Xamarin.Android开发实践(二) 一.准备 开始学习本教程前必须先完成该教程http://www.cnblogs.com/yaozhenfa/p/xamarin_android_qu ...

  3. Xamarin.Android开发实践(一)

    原文:Xamarin.Android开发实践(一) 一.准备工作 1.创建一个空的解决方案,并命名为Phoneword 2.右击解决方案 新建->新建项目 并命名为Phoneword_Droid ...

  4. Xamarin.Android开发实践(三)

    原文:Xamarin.Android开发实践(三) 一.前言 用过Android手机的人一定会发现一种现象,当你把一个应用置于后台后,一段时间之后在打开就会发现应用重新打开了,但是之前的相关的数据却没 ...

  5. Xamarin.Android开发实践(十四)

    Xamarin.Android之ListView和Adapter 一.前言 如今不管任何应用都能够看到列表的存在,而本章我们将学习如何使用Xamarin去实现它,以及如何使用适配器和自定义适配器(本文 ...

  6. Xamarin.Android开发实践(十七)

    Xamarin.Android之定位 一.前言 打开我们手中的应用,可以发现越来越多的应用使用了定位,从而使我们的生活更加方便,所以本章我们将学习如何在Xamarin中进行定位的开发. 二.准备工作 ...

  7. Xamarin.Android开发实践(八)

    Xamarin.Android其他类型的服务 一.前言 前面我们已经学了关于服务的很多知识,但是对于真实的开发那些远远不够,通过这节我们将学习其他类型的服务,比如前台服务.IntentService和 ...

  8. Xamarin.Android开发实践(七)

    Xamarin.Android广播接收器与绑定服务 一.前言 学习了前面的活动与服务后,你会发现服务对于活动而言似乎就是透明的,相反活动对于服务也是透明的,所以我们还需要一中机制能够将服务和活动之间架 ...

  9. Xamarin.Android开发实践(十五)

    Xamarin.Android学习之应用程序首选项 一.前言 任何App都会存在设置界面,如果开发者利用普通控件并绑定监听事件保存设置,这 一过程会非常的枯燥,而且耗时.我们可以看到Android系统 ...

随机推荐

  1. 使用LAMP创建基于wordpress的个从博客站点

    參考: http://blog.csdn.net/ck_boss/article/details/27866117 一.mysql配置 1.安装mysql yum install mysql-serv ...

  2. Android 开发UI牛博[转]

    Android 新兴的UI模式——侧边导航栏 侧边导航栏也就是大家熟知的SliddingMenu,英文也叫Fly-In App Menu.Side Navigation等.当然谷歌现在已经推出类似这个 ...

  3. 2.词法结构-JavaScript权威指南笔记

    今天是第二章.所谓词法结构(lexical structure),就是写代码中最基本的东西,变量命名,注释,语句分隔等,这是抄书抄的... 1.字符集,必须是Unicode,反正Unicode是ASC ...

  4. SQL Server索引进阶:第九级,读懂执行计划

    原文地址: Stairway to SQL Server Indexes: Level 9,Reading Query Plans 本文是SQL Server索引进阶系列(Stairway to SQ ...

  5. Node.js笔记4

    4. 文件系统 fs fs模块是文件操作的封装,提供了同步跟异步操作2个版本 * fs.readFile(filename,[encoding],[callback(err,data)]) 是最简单的 ...

  6. css3选择器的比较(三) -- 元素选择器 (+, ~)

    元素选择器中w3cschool中有些翻译不太准确 比如 +:其实是与element1元素同级,位于element1元素之后的第一个element2元素 ~:其实是与element1元素同级,位于ele ...

  7. zoj 3490

    蛋都疼了,高了半天,Output Limit Exceeded 原来是输入的问题,我靠!!以后还是用输入输出c++好,这尼玛!!郁闷!!!!! #include<stdio.h> #inc ...

  8. C++运算符重载为非成员函数

    #include<iostream> using namespace std; class Complex{ public: Complex(double r=0.0,double i=0 ...

  9. Retrofit2 上传图片等文件

    普通写法: //创建表单的普通字段public static RequestBody createFormBody(String content) { RequestBody body = Reque ...

  10. Linux中fork()函数详解(转)

    一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同, ...