使用 Visual Studio 生成第一個 Xamarin.Android 應用程序,並進一步了解使用 Xamarin 進行 Android 應用程序開發的基礎知識。在此過程中,會介紹生成和部署 Xamarin.Android 應用程序所需的工具、概念和步驟。
第 1 部分:快速入門
在本指南的第一部分,用戶將創建一個應用程序,該應用程序可將用戶輸入的字母數字電話號碼轉換為數字電話號碼,然后呼叫該號碼。
第 2 部分:深入了解
在本文檔的第二部分,將回顧生成的應用程序,並從根本上了解 Android 應用程序的工作原理。
查看項目中的項,查看每個文件夾及其用途:
-
Properties – 包含 AndroidManifest.xml 文件,該文件描述了對 Xamarin.Android 應用程序的所有要求(包括名稱、版本號和權限),此外還包括.NET 程序集元數據文件 AssemblyInfo.cs,可以在此文件中填寫一些應用程序相關的基本信息。
-
引用 – 包含生成和運行應用程序所需的程序集。如果展開“引用”目錄,可查看對 .NET 程序集(如 System、System.Core 和 System.Xml)的引用以及對 Xamarin 的 Mono.Android 程序集的引用。
-
Assets – 包含應用程序需要運行的文件(包括字體、本地數據文件和文本文件)。此處包括的文件可通過生成的
Assets
類訪問。有關 Android 資產的詳細信息,請參閱 Xamarin 使用 Android 資產指南。 -
Resources – 包含應用程序資源,例如字符串、圖像和布局。可以通過生成的
Resource
類訪問代碼中的這些資源。 Android 資源指南提供有關“資源” 目錄的更多詳細信息。 應用程序模板在 AboutResources.txt 文件中還包含有“資源”的簡明指南。
1、資源
“資源”目錄包含 4 類文件夾(drawable、layout、mipmap 和 values),還有一個名為 Resource.designer.cs 的文件 。
-
drawable – 可繪制目錄包含可繪制資源,如圖像和位圖。
-
mipmap – mipmap 目錄包含適用於不同啟動器圖標密度的可繪制文件。 在默認模板中,drawable 目錄包含應用程序圖標文件“Icon.png” 。
- layout – 布局目錄包含 Android 設計器文件 (.axml),該文件定義每個屏幕或活動的用戶界面。 該模板創建名為 activity_main.axml 的默認布局 。
-
values – 此目錄包含存儲簡單值(如字符串、整數和顏色)的 XML 文件。 該模板創建名為 Strings.xml 的文件,用於存儲字符串值。
代碼中使用:
string info = this.Resources.GetString(Resource.String.button_bundle_info);
-
Resource.designer.cs – 也稱為
Resource
類,此文件是一個分部類,存放分配給每個資源的唯一 ID。它由 Xamarin.Android 工具自動創建,並在必要時重新生成。不應手動編輯此文件,因為 Xamarin.Android 將覆蓋對其進行的任何手動更改。
更多查看:Android資源
2、應用基礎知識和體系結構基礎知識
Android應用程序不具有單一入口點;也就是說,應用程序中沒有操作系統可調用來啟動該應用程序的任何代碼行。相反,當 Android 實例化應用程序的一個類時,會啟動該應用程序,在此期間Android 將整個應用程序的進程加載到內存中。
設計復雜應用程序或與 Android 操作系統交互時,Android 的這一特有功能極其有用。 但是,這些選項也使 Android 在處理 Phoneword 應用程序等基本方案時變得復雜。 出於此原因,分兩種情況來探索 Android 體系結構。本指南剖析使用 Android 應用最常見入口點(第一個屏幕)的應用程序。在了解 Android 多屏幕中,討論了以不同方式啟動應用程序,全面探討了 Android 體系結構的復雜性。
在仿真器或設備中首次打開 Phoneword 應用程序時,操作系統會創建第一個Activity,Activity是特殊的 Android 類,對應於單個應用程序屏幕,負責繪制和支持用戶界面。 Android 創建應用程序的第一個Activity時,會加載整個應用程序:
由於 Android 應用程序中沒有線性發展(可以通過多個點啟動應用程序),Android 采用一種獨特方式來跟蹤哪些類和文件組成應用程序。 在 Phoneword 示例中,將向名為“Android Manifest” 的特殊 XML文件注冊組成應用程序的所有部分。 “Android Manifest” 的作用是跟蹤應用程序的內容、屬性和權限,並將這些信息告知 Android 操作系統。 可以將 Phoneword 應用程序當作單一活動(屏幕)和由 Android 清單文件捆綁在一起的資源文件和幫助程序文件的集合,如以下關系圖所示:
以下幾個部分將探索 Phoneword 應用程序各部分的關系;使你能更好地理解上面的關系圖。 此探索先從用戶界面開始,會討論 Android 設計器和布局文件。
3、用戶界面
activity_main.axml 是應用程序中第一個屏幕的用戶界面布局文件 。 .axml 指示這是 Android 設計器文件(AXML 表示 Android XML,名稱 Main 對 Android 而言是任意的 – 可將布局文件命名為其他名稱。在IDE中打開activity_main.axml 時,會顯示名為“Android Designer”的 Android 布局文件的可視編輯器 :
TranslateButton 的 ID 設置為 @+id/TranslateButton
:
設置 TranslateButton 的 id
屬性時,Android Designer 會將 TranslateButton 控件映射到 Resource
類,並為其分配 TranslateButton
的資源 ID 。 通過將可視控件映射到類,可以找到並使用 TranslateButton 和應用代碼中的其他控件。 當你剖析為控件提供支持的代碼時,會更詳細地了解這一內容。 此時,只需知道控件的代碼表示形式是通過 id
屬性鏈接到設計器中控件的可視表示形式即可。
源視圖
在設計界面上定義的所有內容都會轉換成 XML,以供 Xamarin.Android 使用。 Android 設計器提供源視圖,此源視圖包含從可視化設計器生成的 XML,可以切換到設計器視圖左下角的“源” 面板以查看此 XML
4、Activities和活動生命周期
Activity
類包含為用戶界面提供支持的代碼,activity負責響應用戶交互,並創建動態用戶體驗。
- Activity 類
Phoneword 應用程序只有一個屏幕(活動)。為屏幕提供支持的類稱為MainActivity
,位於MainActivity.cs 文件中,名稱 MainActivity
在 Android 中沒有特別的意義 – 雖然約定是命名應用程序 MainActivity
中的第一個活動,但 Android 並不在意將其命名為其他名稱。
打開 MainActivity.cs 時,可以看到,MainActivity
類是 Activity
類的子類 並且活動標有 Activity特性:向 Android 清單注冊Activity,這能讓 Android 知道此類是該清單所管理的Phoneword 應用程序的一部分。
特性中:Label
屬性設置將顯示在屏幕頂部的文本【在values文件夾下的string.xml中管理】;MainLauncher
屬性告知 Android 在啟動應用程序時顯示此活動。 如了解 Android 多屏幕指南中所述,當你向應用程序添加更多活動(屏幕)時,此屬性會變得很重要。
- 活動生命周期
在 Android 中,活動會根據與用戶的交互經歷生命周期的不同階段。可以對活動進行創建、啟動和暫停、恢復和銷毀等操作。Activity
類包含這些方法,系統會在屏幕生命周期的特定時間點調用這些方法。
通過重寫 Activity
生命周期方法,可以控制活動的加載方式和與用戶的互動方式,甚至還可以控制活動從設備屏幕消失后會發生的情況。 例如,可以重寫生命周期方法,以執行以下重要任務:
-
OnCreate – 創建視圖、初始化變量,並執行在用戶能看到活動之前其他必須完成的准備工作。只有將活動加載到內存時,才會調用此方法一次。【向用戶顯示屏幕之前】
-
OnResume – 執行每當活動返回到設備屏幕時必須發生的任何任務。【從主屏幕再次回到app也會調用此方法】
-
OnPause – 執行每當活動離開設備屏幕時必須發生的任何任務。【單擊home鍵,離開app時】
在“Activity
”中將自定義代碼添加到生命周期方法時,您將覆蓋該生命周期方法的基本實現。 您可以利用現有的生命周期方法(已附加一些代碼),然后使用自己的代碼擴展該方法。 您可以從方法內部調用基本實現,以確保原始代碼(base.OnCreate())在新代碼之前運行。 下一部分將說明一個示例。
活動生命周期是Android的重要組成部分。 完成入門系列后,如果您想了解有關活動的更多信息,請閱讀活動生命周期指南。
OnCreate
protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); // Set our view from the "main" layout resource SetContentView (Resource.Layout.activity_main); // Additional setup code will go here }
Bundle:從字符串值到各種可打包類型的映射
OnCreate中加載在 Android Designer中創建的用戶界面:請調用 SetContentView
並向其傳遞布局文件的資源布局名稱:activity_main.axml ,布局位於 Resource.Layout.activity_main
當 MainActivity
開始運行后,會基於 activity_main.axml 文件的內容創建一個視圖 。
准備好布局文件后,可以開始查找控件,若要查找控件,請調用 FindViewById
,並傳入控件的資源 ID。
// Get our UI controls from the loaded layout EditText phoneNumberText = FindViewById<EditText>(Resource.Id.PhoneNumberText); TextView translatedPhoneWord = FindViewById<TextView>(Resource.Id.TranslatedPhoneword); Button translateButton = FindViewById<Button>(Resource.Id.TranslateButton);
現在布局文件中已具有對控件的引用,可以開始對其進行編程,以響應用戶交互。
響應用戶交互
在 Android 中, Click
事件偵聽用戶的觸控,在此應用中,Click
事件將由 lambda 處理,不過也可改用委托或命名事件處理程序。
translateButton.Click += (sender, e) => { // Translate user's alphanumeric phone number to numeric string translatedNumber = PhoneTranslator.ToNumber(phoneNumberText.Text); if (string.IsNullOrWhiteSpace(translatedNumber)) { translatedPhoneWord.Text = string.Empty; } else { translatedPhoneWord.Text = translatedNumber; } };
5、為不同的屏幕密度設置圖標
Android 設備具有不同的屏幕大小和分辨率,不是所有圖像都能清晰顯示在屏幕上。
考慮到這一點,最好將不同分辨率的圖標添加到 Resources文件夾。 Android 提供了不同版本的 mipmap 文件夾來處理不同密度的啟動器圖標,包括:
針對中等密度屏幕的 mdpi、針對高密度屏幕的 hdpi,以及針對超高密度屏幕的 xhdpi、xxhdpi 和 xxxhdpi 。 不同大小的圖標存儲在相應的 mipmap- 文件夾中 。
各文件夾下:
ic_launcher:桌面圖標【可以在設置->更多->應用程序中查看】,
ic_launcher_background:背景圖,
ic_launcher_foreground:前景圖,
ic_launcher_round:圓形圖【屏幕上的】,
並非每個人都具有可用於創建自定義圖標和啟動圖像(讓應用與眾不同)的設計器。下面是幾種生成自定義應用圖像的備選方法:
-
Android Asset Studio – 是一個基於 Web 的瀏覽器生成器,針對所有類型 Android 圖標,帶有其他有用社區工具的鏈接。 在 Google Chrome 中性能最佳。
-
Visual Studio – 可以用於直接在 IDE 中為應用創建簡單圖標集。
-
Glyphish – 可免費下載和購買的高質量預生成圖標集。
-
Fiverr – 從各種設計器中進行選擇以便為你創建圖標集(最低 5 美元)。 可以漫無目標,不過如果需要動態設計的圖標,這是很好的資源。
有關圖標大小和要求的詳細信息,請參閱 Android 資源指南。
應用程序基礎知識
可訪問性
API級別
1、Android資源
新增加資源:eg,my_image_name .png【約定用下划線,小寫】,並將其生成操作設置為:Android資源
2、活動生命周期方法
一個Activity活動就是一個界面的布局。參考:onResume什么時候執行,執行幾次的問題
程序正常啟動時:onCreate()->onStart()->onResume();
onCreate()在活動第一次創建時被調用,主要用於加載布局。
onStart()這個方法在活動由不可見變為可見的時候調用。
onResume()這個方法在活動准備好和用戶進行交互的時候調用。此時的活動一定位於返回棧的棧頂,並且處於運行狀態。
三種調用的場景:
一個Activity啟動另一個Activity: onPause()->onStop(), 再返回:onRestart()->onStart()->onResume()
程序按back 退出: onPause()->onStop()->onDestory(),再進入:onCreate()->onStart()->onResume();
程序按home 退出: onPause()->onStop(), 再進入:onRestart()->onStart()->onResume();
OnCreate
OnCreate是創建活動時要調用的第一個方法,OnCreate
始終需要重寫,以執行活動可能需要的任何啟動初始化,如:
- 創建視圖
- 初始化變量
- 將靜態數據綁定到列表
OnCreate
采用一個綁定參數,該參數是在綁定不為 null 時用於存儲和傳遞狀態信息和活動之間的對象的字典,這表示活動正在重新啟動,應從上一個實例還原其狀態。
OnStart
OnCreate
完成后 , 系統始終會調用 OnStart。 如果活動在活動可見之前需要執行任何特定的任務,例如刷新活動中視圖的當前值,則活動可能會重寫此方法,調用此方法之后Android 將立即調用OnResume
。
OnResume
當活動准備好開始與用戶交互時,系統將調用OnResume 【Activity 開始跟用戶交互之前會調用 onResume()】。 活動應重寫此方法以執行如下任務:
- 斜向上幀速率(游戲開發中的常見任務)
- 開始動畫
- 偵聽 GPS 更新
- 顯示任何相關的警報或對話框
- 連接外部事件處理程序
OnPause
當系統要將活動放入背景中或活動被部分遮蓋時,將調用OnPause 。 如果活動需要,則應重寫此方法:
-
提交永久性數據的未保存更改
-
銷毀或清理使用資源的其他對象
-
增加幀速率和暫停動畫
-
注銷外部事件處理程序或通知處理程序(即綁定到服務的程序)。 必須執行此操作以防止活動內存泄露。
-
同樣,如果活動顯示了任何對話框或警報,則必須用
.Dismiss()
方法對其進行清理。
在調用OnPause后,可能會調用以下兩個方法:
1、OnResume:if the Activity is to be returned to the foreground.
2、OnStop:if the Activity is being placed in the background
OnStop
當用戶不再顯示該活動時,將調用OnStop 。 發生以下情況之一時,會發生這種情況:
- 正在啟動新活動,並覆蓋此活動。
- 現有活動將進入前台。
- 正在銷毀活動。
OnDestroy
OnDestroy是在將其銷毀並從內存中完全刪除之前,在活動實例上調用的最終方法。
大多數活動將不會實現此方法,因為大多數清理和關閉操作都是通過OnPause和OnStop方法完成的;而需要重寫OnDestroy方法一般是用來清理長時間運行的可能會泄漏的資源,例如 在OnCreate中啟動的后台線程。
OnRestart
對於應該在OnRestart中實現哪種邏輯,沒有通用的指導原則。這是因為無論正在創建活動還是重新啟動活動,都始終調用OnStart,因此活動所需的任何資源都應該在OnStart中初始化,而不是在OnRestart中初始化。
3、Back vs. Home
程序按back 退出: onPause()->onStop()->onDestory(),再進入:onCreate()->onStart()->onResume();
程序按home 退出: onPause()->onStop(), 再進入:onRestart()->onStart()->onResume();
按Back鍵會銷毀程序,home不會,只是退到后台線程。
4、Managing State Throughout the Lifecycle
在停止或者銷毀時,系統提供一種保存狀態(實例狀態)的機會,三種方式:
- android采用稱之為Bundle的字典(key/value) 來保存原始值
- Creating a custom class that will hold complex values such as bitmaps.
- 繞過配置更改生命周期,並承擔維護活動狀態的全部責任。
4.1、Bundle介紹
Bundle不適合保存復雜數據(如 位圖)
活動提供一些方法來幫助在捆綁包中保存和檢索實例狀態:
-
OnSaveInstanceState–此操作由 Android 在活動被銷毀時調用。 如果活動需要保留任何鍵/值狀態項,則這些活動可以實現此方法。
-
OnRestoreInstanceState–在OnCreate方法完成后將調用此方法,並為Activity提供了另一個在初始化完成后恢復其狀態的機會。
1.OnSaveInstanceState
當活動正在停止時,將調用OnSaveInstanceState 。 它將接收一個捆綁參數,活動可在其中存儲其狀態。 當設備遇到配置更改時【例如 改變屏幕方向,橫屏豎屏】,活動可以使用Bundle
傳入的對象通過重寫OnSaveInstanceState
來保留活動狀態。
保存活動中的暫時性數據【eg 計數器】,而控件的Text值不會改變。
參考:onSaveInstanceState()和onRestoreInstanceState()使用詳解
當系統開始停止您的Activity時,它會調用onSaveInstanceState()(1),以便您可以指定要保存的其他狀態數據,以防Activity必須重新創建實例。如果Activity被破壞並且必須重新創建相同的實例,則系統將(1)中定義的狀態數據傳遞給onCreate()方法(2)和onRestoreInstanceState()方法(3)。
注意
1、如果是用戶自動按下Home鍵,是不會觸發onSaveInstanceState()和onRestoreInstanceState()的。
2、每次用戶旋轉屏幕時,您的Activity將被破壞並重新創建。當屏幕改變方向時,系統會破壞並重新創建前台Activity,因為屏幕配置已更改,您的Activity可能需要加載替代資源(例如布局)。即會執行onSaveInstanceState()和onRestoreInstanceState()的。
2.OnRestoreInstanceState
還原狀態,一般在OnCreate中還原狀態,而不用重寫OnRestoreInstanceState。
4.2 保存復雜數據
通過重寫OnRetainNonConfigurationInstance並返回包含要保存的數據的Java.Lang.Object
實例來保存數據。 使用OnRetainNonConfigurationInstance
保存狀態有兩個主要優點:
-
從
OnRetainNonConfigurationInstance
返回的對象對更大、更復雜的數據類型執行良好的工作,因為內存會保留此對象。 -
OnRetainNonConfigurationInstance
方法將按需調用,並且僅在需要時調用。 這比使用手動緩存更經濟。
5、Service
- 綁定服務
實現和使用綁定服務
為了使 Android 應用程序使用綁定的服務,必須實現以下
- 新建服務。擴展
Service
類並實現生命周期回調方法 –此類將包含執行服務所需工作的代碼。【eg:一個告訴用戶服務啟動的時間和運行時間的方法api】 - 創建一個實現
IServiceConnection
接口的類,這個接口提供供Android 調用的回調方法(OnServiceConnected),以便在服務連接發生更改時通知客戶端,eg:客戶端已連接或斷開連接到服務.。服務連接還將提供對對象(Binder)的引用,客戶端可使用該對象直接與服務交互。 - 創建一個實現
IBinder接口的類,
IBinder接口提供了客戶端用來與服務進行通信的 API。 Binder 可以提供對綁定服務的引用、允許直接調用方法或Binder 可以提供一個客戶端 API,用於封裝和隱藏應用程序中的綁定服務。IBinder
必須提供遠程過程調用所需的代碼。 不需要(或建議)直接實現IBinder
接口。 相反,應用程序應該擴展Binder類型,它提供IBinder所需的大部分基本功能。 - 啟動Activity並綁定到服務。一旦 service connection, binder, and service 被創建,Android 應用程序負責啟動該服務並將其綁定到它。