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 }
View Code

 

 

這里我們通過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         }
View Code

 

 

通過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         }
View Code

 

 

所有的代碼如下所示:

 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 }
View Code

 

 

四、利用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         }
View Code

 

 

可以看到我們給這個方法加了一個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 }
View Code

 

 

六、解決翻轉后重復執行

做到這步的可以在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數據解析的方法,還有在活動如何保存當前的狀態。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM