android實踐
① 基於android系統的手機游戲的開發
如果你有興趣為Android平台開發游戲,有很多你需要了解的東西。如果你有過游戲開發經驗,那麼轉移到移動平台上來將不是特別困難。你主要只需學習其架構以及API就行了。如果你是一名游戲開發新手,我總結了一張列表,上面有你必需知道的東西,供你起步用。這些知識適用於很多類型的游戲,包括動作類、策略類、模擬類和益智類。Android是一個基於java的環境。這對初學者來說是個好消息,因為相對於C,Java被廣泛認為是一門更容易上手的語言,它是移動開發的規范。Google也做了一件出色的工作,它將API文檔化並提供示例代碼供使用。其中有個叫做APIDemos的示例幾乎展示了所有API的功能。如果你熟悉Java並且用過Eclipse,要讓你的第一個應用跑起來那是相當簡單。如果你以前從沒寫過代碼,在你前進路上還要學習很多,但別氣餒。
獲取SDK
新手上路的第一步便是獲取AndroidSDK(軟體開發工具包)。SDK里有一個核心類庫,一個模擬器,一些工具和示例代碼。我強烈建議使用Eclipse和AndroidEclipse插件。如果你玩Android的話,EclipseIDE對Java開發者來說很好用。如果這是你第一次開發Java項目,你可能會需要下載全套JDK,它裡麵包括簽名和部署你的應用程序的一些工具。
學習應用程序架構
別急著一頭扎進開發的海洋里,理解Android應用程序架構是很重要的。如果你不學一下,你設計出來的游戲在線下將很難調試。你將需要理解、Activities、Intents以及它們怎樣相互聯系。Google提供了很多有用的架構信息。真正重要的是要理解為什麼你的游戲需要多於一個的Activity,以及什麼才是設計一個有良好用戶體驗的游戲。要理解這些,首先要了解什麼是Activity生命周期。
學習Activity生命周期
Activity生命周期由Android操作系統來管理。你的activity創建、恢復、暫停、銷毀都受操作系統的支配。正確處理這些事件是很重要的,這樣應用程序才能表現良好,做用戶認為正確的事。在你設計你的游戲之前了解所有這些是如何工作的是件好事,因為以後你可以為自己節省調試時間和昂貴的重新設計時間。對大多數應用來說,默認的設置將工作正常,但對於游戲,你可能需要考慮將標志打開。當設置為默認時,Android在它認為合適時會創建activity的新實例。對於游戲來說,你可森余能只需要一個游戲activity的實例。這對於你要怎樣管理事務的狀態有些影響,但對於我來說,這解決了一些資源管理的問題,應予以考慮。
主循環
根據你寫的游戲的類型敏春賣,你可能需要也可能不需要一個主循環。如果你的游戲不依賴於時間或者它僅僅對用戶所做的加以回應,並且不做任何視覺上的改變,永遠等待著用戶的輸入,那麼你就不需要主循環。如果你寫的是動作類游戲或者帶有動畫、定時器或任何自動操作的游戲,你應該認真考慮下使用主循環。
游戲的主循環以一個特定的順序通常盡可能多的在每秒鍾內「滴答」提醒子系統運行。你的主循環需要在它自己的線程里運行,原因是Android有一個主用戶界面線程,如果你不運行自己的線程,用戶界面線程將會被你的游戲所阻塞,這會導致Android操作系統無法正常的更新任務。執行的順序通常如下:狀態,輸入,人工智慧,物理,動畫,聲音,錄像。
更新狀態意思是管理狀態轉換,例如游戲的結束、人物的選擇或下一個級別。很多橋逗時候你需要在某個狀態上等上幾秒鍾,而狀態管理應該處理這種延遲,並且在時間過了之後設置成下一個狀態。
輸入是指用戶按下的任何鍵、對於滾動條的移動或者用戶的觸摸。在處理物理之前處理這些是很重要的,因為很多時候輸入會影響到物理層,因而首先處理輸入將會使游戲的反應更加良好。在Android里,輸入事件從主用戶界面線程而來,因此你必須寫代碼將輸入放入緩沖區,這樣你的主循環可以在需要的時刻就從緩沖區里取到它。這並非難事。首先為下一個用戶輸入定義一個域,然後將或函數設為接到一個用戶動作就放到那個域里,有這兩步就夠了。如果對於給定游戲的狀態,這是一個合法的輸入操作,那麼所有輸入需要在那一刻做的更新操作都已經定下來了,剩下來就讓物理去關心怎樣響應輸入吧。
人工智慧所做的類似於用戶在決定下一個要「按」哪個按鈕。學習怎樣寫人工智慧程序超出了這篇文章的范圍,但大體的意思是人工智慧會按照用戶的意圖來按按鈕。這些也有待物理去處理和響應吧。
物理可能是也可能不是真正的物理。對於動作類游戲來說,關鍵點是要考慮到上一次更新的時間、正在更新的當前時間、用戶輸入以及人工智慧,並且決定它們朝著什麼方向發展和是否會發生沖突。對於一個你可視化地抓取一些部件並滑動它們的游戲來說,物理就是這個游戲中滑動部件或者使之放入合適的位置的部分。對於一個小游戲來說,物理即使這個游戲中決定答案是錯還是對的部分。你可能將其命名為其他東西,但每個游戲都有一個作為游戲引擎的紅肉部分(譯者註:可能是主體部分的意思),在這篇文章里,我把這部分稱為物理。
動畫並非像在游戲里放入會動的gif圖片那樣簡單。你需要使得游戲能在恰當的時間畫出每一幀。這並沒有聽起來那麼困難。保留一些像isDancing、danceFrame和那樣的狀態域,那樣動畫更新便能決定是否可以切換到下一幀去了。動畫更新真正做的事就那麼多。真正來顯示動畫的變化是由錄像更新來處理的。
聲音更新要處理觸發聲音、停止聲音、音量變化以及音調變化。正常情況下當寫游戲的時候,聲音更新會產生一些傳往聲音緩沖區的位元組流,但是Android能夠管理自己的聲音,因而你的選擇將是使用SoundPool或者MediaPlayer。它們都需要小心處理以免出錯,但你要知道,因為一些底層實現細節,小型、低比特率的聲音文件將帶來最佳的性能和穩定性。
錄像更新要考慮游戲的狀態、角色的位置、分數、狀態等等,並將一切畫到屏幕上。如果使用主循環,你可能需要使用SurfaceView,並做一個「推」繪制。對於其他視圖,視圖本身能夠調用繪制操作,主循環不必處理。SurfaceView每秒產生的幀數最多,最適合於一些有動畫或屏幕上有運動部件的游戲。錄像更新所要做的工作是獲取游戲的狀態,並及時地為這個狀態繪制圖像。其他的自動化操作最好由不同的更新任務來處理。
3D還是2D?
在開始寫游戲之前,你要決定是做3D的還是2D的。2D游戲有一個低得多的學習曲線,一般更容易獲得良好的性能。3D游戲需要更深入的數學技能,並且如果你不在意的話會有性能問題產生。如果你打算畫比方框和圓圈更復雜的圖形,還需要會使用3DStudio和Maya那樣的建模工具。Android支持OpenGL用來3D編程,並且在OpenGL方面有很多很好的教程可供學習。
建立簡單、高質量的方法
上手時,要確保你整個游戲不要就用一個龐大而冗長的方法。如果你遵循我上面描述的主循環模式,這將相當簡單。每個你寫的方法應當完成一個非常特定的任務,並且它就應該無差錯地那樣做。舉例來說,如果你需要洗一副紙牌,你應該寫一個「」的方法,並且該方法就應該只做這一件事。
這是一個適用於任何軟體開發的編碼實踐,但對於游戲開發來說這尤為重要。在一個有狀態的、實時的系統里,調試將變得非常困難。使你的方法盡量的小,一般的經驗法則是每個方法有且僅有一個目的(譯者註:完成且僅完成一個功能)。如果你要為一個場景用編程方式畫一個背景,你可能需要一個叫做「」的方法。諸如此類的任務能夠很快完成,因而你可以按照搭積木的方法來開發你的游戲,而你能夠繼續添加你要的功能,並且不會使得這一切難以理解。
最重要的是效率!
性能是任何游戲的主要問題。我們的目標是使得游戲的反應越快越好,看起來越流暢越好。某些方法如Canvas.drawLine比較慢。並且要將屏幕大小的點陣圖畫到主畫布上,每一幀都是代價昂貴的。如何權衡對於達到最佳性能很有必要。確保管理好你的資源,使用技巧來以最少量的CPU資源完成你的任務。如果性能不好的話,即使是最好的游戲玩起來也沒勁。人們一般對於游戲卡或者響應慢幾乎難以容忍。
提示和技巧
看一下SDK中的示例LunarLander。它使用SurfaceView,這對於一個每秒需要處理最多幀的游戲來說是合適的。如果你要做3D,示例中有GLView可以處理3D顯示的很多初始化工作。對LightRacer來說,我不得不優化把所有東西都畫出來這種方法,否則幀率將會大大地降低。我只在視圖初始化的時候把背景畫進一個點陣圖里一次。路徑放在它們自己的點陣圖里,隨著車手的前進而更新。這兩個點陣圖在每一幀里都被畫進主畫布中去,車手畫在頂端,到最後會有一個爆炸。這種技術使得游戲運行在一個可以玩的程度。
如果適用的話,使得你的點陣圖的大小精確等於你打算畫到屏幕上的大小,這也是個好的實踐。這么做了以後就需要縮放,可以節省CPU資源。
在游戲中始終一致的點陣圖配置(如RGBA8888)。這將會通過減少不同格式之間轉換的時間來節省圖形庫的CPU時間。
如果你決定開發3D游戲但沒有3D方面的知識,你需要挑選一兩本3D游戲編程方面的書並學習線性代數。你最少要理解點積、叉積、向量、單元向量、法線、矩陣和變換。這方面我遇到的最好的書是叫《3D游戲編程和計算機圖形學數學》。
聲音文件要小而且低比特率。需要載入的越少,載入速度越快,游戲所需內存越少。
聲音使用OGG文件,圖片使用PNG文件。
確保釋放所有媒體播放器,當Activity銷毀時空出所有的資源。這能保證垃圾收集器清除了所有東西,也能保證在兩次游戲開始之間沒有內存泄露。
加入Android谷歌小組,尋求社區支持。這里有人可以在開發過程中給你幫助。
最重要的是,花時間測試再測試,確保每一小部分都如你所願地工作。改善游戲是整個開發中最耗時最困難的部分。如果你匆匆將其推向市場,你很可能會使用戶們失望,你會感到你的努力都白費了。你不可能使所有人都喜歡你寫的東西,但你至少要盡量發布你最高質量的作品。
② 【譯】Android材質組件的動手實踐:Dialogs
Android MDC 系列文章:
這篇文章將介紹 Dialogs 組件的功能和API。要了解如何處理Android的Material Components的初始設置(包括Gradle依賴關系和創建應用程序主題),請參閱我的原始文章:
為Android設置Material Components主題
對話框是組件,通常帶有模式窗口,顯示在應用程序內容的前面。它們用於告知用戶可能包含關鍵信息和/或需要做出決定的任務。它們有目的地打斷電流,並一直顯示在屏幕上,直到被解散或採取措施為止,因此應謹慎使用。
從設計的角度來看,可以在不同的場景中使用三種主要類型的對話框:
上面所有這些都具有共同的特徵:遮蓋應用程序內容的背景稀鬆布(可以選擇輕按以關閉對話框)和表面容器。
注意:存在第四種類型: 全屏對話框 。為此, 官方文檔 建議使用 *DialogFragment* 和資源限定符一起確定其顯示方式。這不在本文的討論范圍之內,因此不會涉及。
可以使用來實現所有上述對話框類型 MaterialAlertDialogBuilder 。該構建器類 AlertDialog 使用Material Design規范和主題來配置和實例化。
顯示對話框的基本方法如下:
配置更改(例如設備旋轉)後,上述方法將不會保留對話框。為了實現這一點,我們需要花一段 DialogFragment 時間使用 MaterialAlertDialogBuilder 來提供 Dialog :
DialogFragment 可以使用 導航體系結構組件 顯示,也可以通過 Fragment 或 Activity 通過以下方式手動顯示:
可以通過將參數傳遞給來實現上面(和更多)三種對話框中列出的所有特徵 MaterialAlertDialogBuilder 。下面列出了其中一些。
注意:在以下大多數情況下,將使用硬編碼值。該構建器還提供資源ID的重載。
注意:對話框的中間區域可以被支持文本或一組特定類型的項目佔用。這些不能合並。
存在幾個主題疊加層,用於更改對話框的總體布局。這些主題覆蓋變體繼承自 ThemeOverlay.MaterialComponents.MaterialAlertDialog ,每個都有一個可選的後綴:
實施全局自定義Material AlertDialog 主題疊加層時,請在您的應用程序主題中使用 materialAlertDialogTheme 屬性引用它。
另外,還有一個輔助 MaterialAlertDialogBuilder 構造函數,它接受覆蓋的主題資源ID:
可以使用三個「材料主題」子系統為主題設置「材料警報」對話框: 顏色 , 版式 和 形狀 。我們已經在上面的 「選擇主題疊加層」 部分中顯示了要使用 的主題疊加層 。除此之外, AlertDialog 可以通過擴展樣式並使用屬性 在 主題疊加層中引用自定義樣式。 MaterialAlertDialog.MaterialComponents``alertDialogStyle
有沒有具體的屬性自定義在一個對話框中使用的顏色,但 colorPrimary , colorSecondary , colorSurface 和各自的「關於」在您的應用程序使用的主題會自動調整對話框顏色顏色改變時。
對話框文本元素將採用 fontFamily 您在應用程序主題中定義的屬性。操作按鈕的樣式將根據 textAppearanceButton 您在應用主題中設置的樣式進行設置。
在主題疊加層中,您還可以使用 屬性為正文文本專門設置樣式。
可以使用該 shapeAppearance 屬性自定義對話框背景的形狀。默認為 。
我希望這篇文章對對話框以及如何在您的Android應用中使用對話框提供了一些見識。如果您有任何疑問,想法或建議,那麼我很樂意收到您的來信!
在Twitter上找到我 @ricknout
③ Android性能優化-大解析度圖片最佳實踐
好久沒更新博客了,借著908公司18周年年會這個普(期)天(待)同(紅)慶(包)的日子,來說下安卓中的圖片與內存的關系。
大家都知道安卓中圖片是佔用內存的大戶,在日常開發中也免不了用到圖片,那麼圖片佔用內存與哪些因素有關呢,先直接給結論:
1)與圖片解析度有關;
2)與開發者放的文件目錄有關;
3)與圖片大小沒有半毛錢關系。
舉個例子:
以現在主流1080p手機為例,新建一個空的工程,用一張1080*1080像素圖片來測試:
將圖片放在xxhdpi目錄下,測試內存,效果如下:
大家可以接著嘗試將圖片放到mhdpi目錄 或者xhdpi目錄下,看下內存佔用情況,上面放xxhdpi從圖上看大概佔4M左右,那麼這個值是怎麼計算來的:
放xxhpi下圖片內存佔用 = 1080 *1080 *4 /1024 / 1024 = 4.45M
稍微解釋下公式,像素長*寬*一個像素佔用的位元組數,安卓的色彩模式一個像素佔用的位元組關系如下表:
也就是說,你在布局文件里隨便定義一個imageview,載入一個1080*1080的圖片,顯示的時候,將按一像素4byte計算內存占拆配昌用。
如果你按照上面的步驟嘗試了將圖片放到mdpi目錄或者xhdpi目錄,應該知道結論了,圖片佔用內存成倍數的變大了,看下放mdpi文件夾下的效果:
如果開發者將同樣一張1080*1080像素圖片放到mdpi目錄下,圖片佔用內存=(1080*3)*(1080*3)*4 /1024 /1024 = 40M,比之前放xxdpi目錄下內存高出了9倍,所以:圖片不是亂放的,要謹慎。
現在主流手機解析度1080p以上,建議大圖統一放到xxhdpi目錄下管理。
高解析度圖片常見的導致性能缺陷的場景包括:
1)放錯圖片目錄賣基,導致佔用內存成倍數增長;
2)限定了高寬的imageview組件,載入了超過該尺寸大小的圖片;
3)單色值圖片、loading過渡圖片、對清晰度要求不高的圖片等,強上了大解析度圖片。
這些場景都是在實際開發中遇到過的問題,可能出於設計師的疏忽,可能出於程序猿的隨意,修復這些缺陷的成本很低,但是對內存降低的幫助是指數級的,投入產出比這么高的事情,只能說到這里了。
對應的修復手段很明確了:
1)建議圖片放xxhpdi目錄;
2)限定高寬的imageview,圖片最大尺寸不超過該imageview最大承載高寬;
3)簡單圖片直接下掉,或者壓縮下吧,也可以結合業務背景用背景色等替換。
如果你的項目比較小,人肉去找都可以知道哪些是大分旅扒辨率圖片,那麼檢查下使用是否正確。如果你的項目是一個大型客戶端項目,人工去找就很尷尬了,是的,我想說python大法好,來個腳本吧,無死角搞定所有大解析度圖片可能導致的性能缺陷:
④ Android 開機自啟動service實踐
Android 設備啟動的時候,會發送android.intent.action.BOOT_COMPLETED的廣播,監聽這個廣播來實現開機自啟動。
1) 創建需要的service和 BroadcastReceiver
2) 在AndroidManifest.xml 注冊service 和BroadcastReceiver
3)申明許可權
```
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
}
⑤ ANDROID多渠道快速打包實踐
參考資料:
美團Android自動化之旅—生成渠道包
Android批量打包提速
AndroidMultiChannelBuildTool
背景
隨著發版需要,每次發版所需渠道包越來越多(現在差不多有一百個左右了),正常gradle打包由於耗時效率過低已無法滿足需求,開始了android多渠道快速打包實踐。
方法
下面主要介紹兩種快速打包的方式:
1、類似美團的方式,在META-INF中寫入渠道名的空文件,用於讀取空文件。 美團Android自動化之旅—生成渠道包
2、在apk末尾動態寫入渠道信息。 一種動態為apk寫入信息的方案
其實這兩種方式都是同一個原理,替換以前從manifest中讀取渠道號的方式,而使用新的獲取方式(渠道號如何寫入就如何讀取)。
所以這首先需要客戶端(重要!):
1、統一應用中獲取渠道的方式並替換之前的(最好兼容)。
2、注意第三方SDK渠道號的傳入,比如友盟sdk,否則第三方會使用默認從manifest中讀取的方式。
下面介紹一種已經測試過的方法(git上開源項目 AndroidMultiChannelBuildTool )
1、安裝環境由於腳本環境是使用python語言,所以需要我們 安裝環境 。
2、導入項目導入開源項目 AndroidMultiChannelBuildTool ),並把想要批量打包的apk文件拷貝到PythonTool目錄下(與py同級),運行py腳本即可打包完成。
以上基本實現快速打包,經過測試一分鍾百十個無壓力。另外需要注意這種方式只適用於打包需求一致渠道號不同,不適用特殊定製渠道。
備註:9月21日補充快速打包java版本,詳見 AndroidMultiChannelBuildTool-Java-master