上一篇交代了我Xamarin填坑的背景,大概聊了聊第一步環(huán)境配置,第二步創(chuàng)建項(xiàng)目和開發(fā)框架選擇。如果有一個可用的梯子,這部分基本不會出錯。


 

  接下來就具體聊一聊寫代碼的過程中遇到的一些事兒。

  第三步是碼代碼:

  ①Http相關(guān):

  我做的項(xiàng)目是一個校園助手,目前提供的功能絕大多數(shù)是查詢功能?;蛘哒f,就是簡單的爬蟲,從校園服務(wù)器上爬取相關(guān)網(wǎng)頁。因此,結(jié)合校園網(wǎng)站以及我的自身需求,我寫了一個簡單的用于發(fā)送Http請求的服務(wù)類HttpService,封裝了一些Request方法:

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn) View Code

這段代碼本身沒有問題,但是在Xamarin中有個坑。由于需要用到gb2312編碼方式,但是我在調(diào)試安卓項(xiàng)目的時候,卻遇到類似“not support 936 code page”錯誤,解決的辦法就是在安卓項(xiàng)目屬性中添加CJK編碼方式支持。

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

  這兒有一個最佳實(shí)踐,分享自周岳老師

一般所有的Http請求通過HttpClient發(fā)起,每一個HttpClient的對象都幫我們維護(hù)了Http請求的一些基本信息,包括本地緩存,Cookie等。那默認(rèn)的,如果Xamarin中直接使用HttpClient,它的實(shí)現(xiàn)完全是.net的實(shí)現(xiàn)方式。在這兒,可以通過ModernHttpClient來完成一些優(yōu)化。

在創(chuàng)建HttpClient的時候,可以傳入一個ModernHttpClient.NativeMessageHandler實(shí)例,作為默認(rèn)的Handler。這樣在Android平臺會使用OKHttp來執(zhí)行一些Http請求,細(xì)節(jié)可以看作者的Github

HttpClient client=new HttpClient(new ModernHttpClient.NativeMessageHandler() );

 

  Nuget:ModernHttpClient

  GitHub:ModernHttpClient

  在Http請求這塊兒,除了上面這個最佳實(shí)踐,其他部分可以100%重用我UWP項(xiàng)目中的代碼?;緹o需任何修改。

 

  ②HTML Parse:

  因?yàn)樾?nèi)網(wǎng)站很少有直接提供REST API服務(wù),所以必須自己從各個頁面解析數(shù)據(jù)。對于Dom的分析,我選擇使用AngleSharp這個工具。這個工具現(xiàn)在已經(jīng)可以支持Xamarin了。

  值得高興的是,個別站點(diǎn)使用了JSON傳送數(shù)據(jù),針對JSON的解析,目前.Net平臺最權(quán)威的就是Newtonsoft.Json這個庫了,配合Newtonsoft.Json以及.Net的dynamic動態(tài)類型,很容易能完成Json的解析。Xamarin完全支持!所以這部分的代碼也是100%重用。

     官網(wǎng):AngleSharp

 

  ③XXXService:

  在上面介紹的Http相關(guān)請求中,為了使用方便,我封裝了一個基本的HttpBaseService類,主要就是這層各種XXXService獲取數(shù)據(jù)。校園助手目前是以查詢?yōu)橹?,包括查詢成績,課表等教務(wù)相關(guān)的信息,查詢一卡通余額,消費(fèi),解/掛失等簡單的個人信息。于是針對不同的功能大類別,我封裝了諸如EduService,InfoService等類,在類中實(shí)現(xiàn)了一些方法,用來完成獲取數(shù)據(jù),解析數(shù)據(jù)的功能。對這些方法的調(diào)用,都是由ViewModel層來完成,所以這部分代碼和UWP項(xiàng)目中的也是所差不多。

 

  ④ViewModel:

  根據(jù)MVVM的特點(diǎn),原則上是一個View對應(yīng)一個ViewModel。ViewModel層和我UWP項(xiàng)目中的一樣,變動不多。但是,在UWP項(xiàng)目中,我使用的是MVVMLight這個框架,而在Xamarin中選擇了微軟自家的Prism,所以在消息通知,頁面導(dǎo)航等方面會有一些不同。下面列舉一些使用Prism MVVM時的一些內(nèi)容。

  •   關(guān)于頁面導(dǎo)航:Prism在頁面導(dǎo)航方面,提供了一個接口Prism.Navigation.INavigationService,采用構(gòu)造函數(shù)注入的方式。

  •   關(guān)于加載數(shù)據(jù)的問題:每當(dāng)創(chuàng)建一個ViewModel,我們希望去獲取一些數(shù)據(jù),可能是存儲在本地的,也可能要從網(wǎng)絡(luò)上獲取的。但是考慮到性能問題,這部分?jǐn)?shù)據(jù)不能放在構(gòu)造函數(shù)里面。

      1.比較好的辦法就是當(dāng)導(dǎo)航到ViewModel對應(yīng)的View的時候,再去加載數(shù)據(jù),Prism框架提供了這樣一個接口來實(shí)現(xiàn)相關(guān)的功能

public interface INavigationAware
{    void OnNavigatedFrom(NavigationParameters parameters);//從當(dāng)前頁面離開時
    void OnNavigatedTo(NavigationParameters parameters);//導(dǎo)航到當(dāng)前頁面時}

      可以通過實(shí)現(xiàn)該接口,然后在OnNavigationTo方法中去加載一些數(shù)據(jù)。當(dāng)然這個接口的作用不限于此,主要作用還是處理頁面導(dǎo)航時傳遞的參數(shù)。

      2.還有一個我在UWP中常用的辦法,就是自定義一個OnLoad方法,然后綁定到View的Loaded事件上面。但這兒有一個很尷尬的問題,Xamarin的Page中并沒有一個Loaded事件,相對變通的是它有一個Appearing事件,可以當(dāng)作Loaded來用。具體的綁定方法如下:

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn) View Code

      上述代碼大致在Page中實(shí)現(xiàn)一個自定義的LoadedCommand,然后在頁面觸發(fā)Apearing事件的時候,調(diào)用該命令的Excute方法,命令則通過數(shù)據(jù)綁定進(jìn)行賦值,與ViewModel中的LoadedCommand相相綁定,這也是為什么把LoadedCommand定義為依賴屬性的原因。

    通過上面提到的1,2兩點(diǎn),就可以在導(dǎo)航到頁面以后加載一些數(shù)據(jù)了,如果配合.net的async/await異步編程模型,就能更加流暢的實(shí)現(xiàn)數(shù)據(jù)加載了。

 

  ④Views:

  針對View的編寫是這次踏坑Xamarin最耗時的部分。雖然Xamarin.Forms可以用Xaml來編寫頁面,但是和UWP的XAML比起來,功能上差不多,體驗(yàn)上卻很不好,尤其是自動補(bǔ)全和智能感知等方面。所以寫代碼會寫的很累。這些其實(shí)還好解決,畢竟熟悉一段時間后就基本沒有障礙了。唯一欠缺的就是針對XAML代碼的Previewer了,雖然今年的Connect()2016大會上,Xamarin Studio里面已經(jīng)集成了初步的Previewer,但目前離正式發(fā)布還有一段距離,尤其是在VS里面。針對這點(diǎn),給出一個稍微便捷的應(yīng)對辦法。使用工具Gorilla-Player,在真機(jī)上預(yù)覽。具體使用可以看他的WIKI,下面展示一個使用該工具的截圖

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

當(dāng)然目前這個工具問題還挺多,比如不支持靜態(tài)資源的引用等。在吐槽的同時,還是需要靜靜的等待官方的previewer正式發(fā)布。

  針對View也有一個最佳實(shí)踐:

因?yàn)楝F(xiàn)在XAML編輯器還不能很好的提供智能感知和自動補(bǔ)全等功能,所以在自己寫一些屬性的時候,很容易出現(xiàn)拼寫錯誤的問題。往往這種錯誤在編譯的時候,并不會被編譯器檢查到,于是錯誤就會發(fā)生在運(yùn)行時,往往耗時耗力。Xamarin為我們提供了一個特性,叫做XamlCompilationAttribute,用來提供編譯程序集時候的XAML拼寫檢查等任務(wù)。他可以應(yīng)用到整個程序集,也可以之應(yīng)用在單個的View上。只需要指定其參數(shù)為XamlCompilationOptions.Compile即可。

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]//用于整個程序集
[XamlCompilation(XamlCompilationOptions.Compile)]//只用于單個Page/View

當(dāng)然XamlCompilation怎么可能會只提供這么一點(diǎn)特性呢?它可以提升整個XAML的性能,通過預(yù)編譯為IL代碼的方式,減少加載XAML的時間。具體看官方文檔:

XamlCompilation(https://developer.xamarin.com/guides/xamarin-forms/xaml/xamlc/)

  

  ⑤數(shù)據(jù)存儲:

  一個完整的App,必須有本地存儲,無論是緩存一些文件,還是存儲一些必要配置信息。Xamarin跨平臺提供了統(tǒng)一的數(shù)據(jù)存儲方式,但是在不同的平臺上,具體實(shí)現(xiàn)是不同的。數(shù)據(jù)存儲方面,我選擇了SQLite這個輕量級的數(shù)據(jù)庫,這也是移動開發(fā)本地存儲最適合的數(shù)據(jù)庫之一了。好在現(xiàn)在也有比較成熟的ORM工具來支持SQLite了。
  Xamarin官方實(shí)例(https://developer.xamarin.com/guides/xamarin-forms/working-with/databases/)
  nuget:sqlite-net-pcl(https://www.nuget.org/packages/sqlite-net-pcl)

 


  補(bǔ)幾張圖結(jié)束本篇

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)     iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)    iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

  在碼代碼的過程中,還遇到過一些其他的坑,以后慢慢更,因?yàn)檫@是連載系列......