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

  • 相关阅读:
    Begin Example with Override Encoded SOAP XML Serialization
    State Machine Terminology
    How to: Specify an Alternate Element Name for an XML Stream
    How to: Publish Metadata for a WCF Service.(What is the Metadata Exchange Endpoint purpose.)
    Beginning Guide With Controlling XML Serialization Using Attributes(XmlSerializaiton of Array)
    Workflow 4.0 Hosting Extensions
    What can we do in the CacheMetaData Method of Activity
    How and Why to use the System.servicemodel.MessageParameterAttribute in WCF
    How to: Begin Sample with Serialization and Deserialization an Object
    A Test WCF Service without anything of config.
  • 原文地址:https://www.cnblogs.com/ShaYeBlog/p/4615574.html
Copyright © 2020-2023  润新知