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数据解析的方法,还有在活动如何保存当前的状态。

时间: 2024-10-12 23:02:20

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

Xamarin.Android开发实践(十四)

Xamarin.Android之ListView和Adapter 一.前言 如今不管任何应用都能够看到列表的存在,而本章我们将学习如何使用Xamarin去实现它,以及如何使用适配器和自定义适配器(本文中的适配器的主要内容就是将原始的数据转换成了能够供列表控件显示的项). 二.简介适配器 在开始之前我们需要先了解下适配器,首先是提供给我们使用的适配器之间的关系: 下面我们将上面的适配器进行简单的介绍: BaseAdapter:顾名思义,就是所以适配器的基类,但是我们不能将其实例化,因为它是一个虚类

Xamarin.Android开发实践(十七)

Xamarin.Android之定位 一.前言 打开我们手中的应用,可以发现越来越多的应用使用了定位,从而使我们的生活更加方便,所以本章我们将学习如何在Xamarin中进行定位的开发. 二.准备工作 因为我们的虚拟机是运行在电脑本地的,自然就没法进行定位了,但是我们可以借助DDMS这个工具帮助我们去调试. 首先要确定你的Android SDK所在的目录,读者可以通过以下方式找到: 工具->选项 然后读者打开该文件夹下的tools文件夹,我们就可以看到里面有很多以bat结果的文件,这个时候我们打开

Xamarin.Android开发实践(十五)

Xamarin.Android学习之应用程序首选项 一.前言 任何App都会存在设置界面,如果开发者利用普通控件并绑定监听事件保存设置,这 一过程会非常的枯燥,而且耗时.我们可以看到Android系统的设置界面里面的选项如此之多,是不是都是这样开发的呢?其实不然,Android已经给 我们提供了专门设计这一功能的技术,叫应用程序首选项,今天我们将学习如何使用他们来开发配置界面以及功能. 二.准备工作 首先需要理解的就是我们设置界面还是需要控件的,但是我们所使用的控件不在是普通的控件,下面我们来简

Xamarin.Android开发实践(十二)

Xamarin.Android之ContentProvider 一.前言 掌握了如何使用SQLiteOpenHelper之后,我们就可以进行下一步的学习.本章我们将会学习如何使用ContentProvider来将数据库方面的操作封装起来,同时它还可以供其他应用访问并操作数据库. 二.概念 首先我们不会急于写代码,而是要搞懂如何利用ContentProvider对数 据库进行操作,因为我们不会直接操作数据库对象,而是通过URI来操作数据库.这就好比你要获取User表的全部内容,那么这个URI就是

Xamarin.Android开发实践(九)

Xamarin.Android之ActionBar与菜单 一.选项卡 如今很多应用都会使用碎片以便在同一个活动中能够显示多个不同的视图.在 Android 3.0 以上的版本中,我们已经可以使用ActionBar提供的Tab来实现这种效果,而不需要我们自己去实现碎片的切换.ActionBar默认是不具备选项 卡功能的,所以我们需要给一个属性赋上对应的枚举,比如下面的方式将开启选项卡. 1 ActionBar.NavigationMode = ActionBarNavigationMode.Tab

Xamarin.Android开发实践(六)

Xamarin.Android通知详解 一.发送通知的机制 在日常的app应用中经常需要使用通知,因为服务.广播后台活动如果有事件需要通知用户,则需要通过通知栏显示,而在Xamarin.Android下的通知需要获取NotificationManager服务,而该服务需要通过GetSystemService获取,同时还要传递一个标识符.获取了通知管理器后我们就可以实例化Notification,然后再由NotificationManager发送出去.这就是整个过程了.下面我们将一一详解通知. 二

Xamarin.Android开发实践(十一)

Xamarin.Android之使用百度地图起始篇 一.前言 如今跨平台开发层出不穷,而对于.NET而言时下最流行的当然还是 Xamarin,不仅仅能够让我们在熟悉的Vs下利用C#开发,在对原生态类库的支持方面也有着非常的好支持,今天我们将会以百度地图类库来介绍如何实用 第三方原生态类库.如果需要在Fragment中使用请跳转到(由网友monosir提供)该篇文章. 二.正文 笔者采用的是3.0.0的版本,需要以下文件: baidumapapi_v3_0_0.jar libBaiduMapSDK

Xamarin.Android开发实践(十六)

Xamarin.Android之Fragment Walkthrough 利用Fragment设计能够兼容不同屏幕的应用 这里我们先围观下最后的成果图,给读者打打气: 普通手机上显示的结果: 在平板上显示的结果: 笔者要郑重声明下,虽然看似是两种不同的显示效果,但是同一个应用,而下面笔者将逐步教会大家如何利用Fragment制作出能够兼容不同屏幕的应用. 准备工作 创建一个项目是必不可少的,并且Android SDK的版本要在3.0以上,建议是4.0因为笔者设定的就是4.0,新建完成之后项目会自

Xamarin.Android开发实践(十三)

Xamarin.Android之SQLite.NET ORM 一.前言 通过<Xamarin.Android之SQLiteOpenHelper>和<Xamarin.Android之ContentProvider>的 学习,我们已经掌握了如何使用特定于该平台的数据库操作.但是这样却和Xamarin所宣称的跨平台相违背了,因为这样我们就需要针对不同的平台编写不同 的代码,而本章将使用Github上的开源项目SQLite.NET去解决这个问题,从而可以实现跨平台,减少代码的重复. 关于该