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

  • 相关阅读:
    SQL 学习随笔
    hibernate查询方式总结基于原生SQL查询(二)
    hibernate查询方式总结(四)之QBC,QBE查询
    Hibernate查询方式汇总之Hql查询(三)
    java 强引用,软引用,弱引用,虚引用
    JAVA-对java平台的理解
    Git SSH本机配置
    Windows下Python3解决 Microsoft Visual C++ 14.0 is required 报错
    checkpoint原理剖析与源码分析
    CacheManager原理剖析与源码分析
  • 原文地址:https://www.cnblogs.com/ShaYeBlog/p/4615574.html
Copyright © 2011-2022 走看看