Xamarin.Android开发实践(四)

Xamarin.Android开发实践(四)

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

Xamarin.Android下获取与解析JSON

一、新建项目

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

Xamarin.Android开发实践(四)

 

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

Xamarin.Android开发实践(四)

 

二、同步请求

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

 

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

Xamarin.Android开发实践(四)

删除其他上面的控件,并拖拽一个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。

 

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

Xamarin.Android开发实践(四)

 

但是我们在编码的过程中绝对不能这么做,因为这样会使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:

Xamarin.Android开发实践(四)

 

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/109387.html原文链接:https://javaforall.net

(0)
上一篇 2021年9月8日 上午6:00
下一篇 2021年9月8日 上午7:00


相关推荐

  • 平均数、众数、中位数、极差、方差、标准差……

    平均数、众数、中位数、极差、方差、标准差……Python 代码实现第一步 添加数据到列表 defnum a iffloat a int a returnint a else returnfloat a 添加数据 li print 请逐条添加数据 若退出请输入 0000 whileTrue print 请输入 amp q

    2026年3月18日
    1
  • 基于 Java GenKit 构建生成式 AI 应用指南(完整版)

    基于 Java GenKit 构建生成式 AI 应用指南(完整版)

    2026年3月16日
    2
  • asio ssl 笔记

    asio ssl 笔记Asio 包含了一个类以及类模板用于基本的 SSL 支持 这个类使得加密通信成为可能 在已经存在的流上层做了一层加密 比如加密一个 TCP 套接字 在创建一个加密流之前 必须要构造一个 SSLcontext 对象 这个对象用于设置 SSL 选项 认证模式 认证文件等 下面用一个客户端的初始化作为说明 ssl contextctx ssl context sslv23 ctx set v

    2026年3月17日
    1
  • pycharm运行结果区显示乱码_windows控制台乱码

    pycharm运行结果区显示乱码_windows控制台乱码解决pycharmTerminal(控制台)乱码问题描述解决方法问题描述环境:ubuntu18.04系统终端:zsh(使用onmyzsh美化过)pycharm2020.3.2解决方法乱码原因还是字体支持的问题,相近的问题见文章ubuntu美化及解决使用zsh后无法运行ROS中的安装PowerLine字体打开pycharm的setting(File->Settings)定位到Editor|ColorScheme|ConsoleFont,修改设

    2025年5月31日
    6
  • CANoe/CANalyzer诊断功能的深入理解以及CAPL诊断编程实现

    CANoe/CANalyzer诊断功能的深入理解以及CAPL诊断编程实现之前和大家分享了CANoe的基础使用(分析、仿真、测试、诊断),这篇文章将继续深入探讨如何使用CANoe/CANalyzer中的诊断功能。诊断用于在将ECU安装到系统之前或之后配置,维护,支持,控制和扩展ECU,例如,一辆车。诊断通常在请求-响应方案中执行:测试仪(客户端)向…

    2022年6月30日
    98
  • Vue(3)webstorm代码格式规范设置与vue模板配置

    Vue(3)webstorm代码格式规范设置与vue模板配置编译器代码格式规范设置通常我们写代码时,代码缩进都是4个空格,但是在前端中,据全球投票统计,建议使用2个空格来进行代码缩进。首先我们打开webstorm中的设置,如果使用的是mac的同学直接使用c

    2022年7月31日
    100

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号