前言
最近完成了移動編程課程的學習,加上其它安卓開發項目的經歷,感覺收穫頗為豐富。故在此總結整理安卓開發中比較常見的一些問題,技巧和指南。
1.開發環境
Android Studio是谷歌基於IntelliJ IDEA社區版開發的,面向安卓開發的免費集成開發環境。其方便快捷的開發調試和可視化UI編輯可以令安卓開發事半功倍。本項目所使用集成開發環境為Android Studio 4.1.1,編程語言為Java,使用JDK 1.8,使用Gradle 4.1.1進行項目工程構建和依賴管理。
2. 項目新建
Android Studio新建項目時選擇一個Activity模板作為默認MainActivity,先選擇Empty Activity作為開始。接着,Minimum SDK指的是本項目所支持的最小安卓SDK,點擊“Help me choose”會出現如下界面幫助選擇合適的安卓最小SDK版本:
圖1 安卓API版本選擇幫助界面
其中CUMULATIVE DISTRIBUTION表示如果支持該安卓版本以上設備,則預估能支持安卓設備占所有安卓設備的百分比。可見Minimum SDK越小所能支持設備越多,但沒有必要一味追求支持更多設備,這需要根據一定的市場調查與經驗來決定。本項目選擇支持默認的安卓6.0及以上。
3.項目結構
3.1 開發模式
安卓開發常見的開發模式有MVC,MVP,MVVM等(詳見本站文章 “學習筆記 | Android開發常用的幾種模式”),其中MVC非常容易上手,結構清晰易懂,為了簡化開發,本項目使用MVC模式進行開發。
3.2 安卓項目文件及目錄結構簡介
- 安卓應用配置文件AndroidManifest.xml: 用於配置包名、應用權限、應用圖標及名稱、主題等基本信息,此外包括了應用的Activity相關配置,沒有在此進行註冊的Activity是不能被啟動的。
- 程序代碼java: 在java目錄下的對應包名中存放包括Activity在內的各java程序文件。
- 資源文件res: 存放用於UI相關的各類資源,主要有:drawable:存放可被繪製的圖形,包括矢量圖和位圖,以及由xml編寫的各類圖層、狀態選擇器等比較實用的前端UI部件。layout: 以xml文件形式編寫的用戶交互界面,可以在Android Studio中進行實時渲染預覽、可視化編輯等。values:arrays.xml: 存放數組,在程序中按照自定義的數組名進行讀取。colors.xml: 存放Hex色值,在程序中按照自定義的顏色名字進行讀取。dimens.xml: 存放尺寸信息。strings.xml: 存放字符串,按照自定義的字符串名進行獲取,方便多語言程序的本土化。themesthemes.xml: 程序主題,包括主色次色和各類樣式。themes.xml(night): 程序夜間主題。mipmap: 存放貼圖文件,如果期望貼圖有放大縮小動畫之類的可以獲得更好的圖像表現。xml: 存放一些其它xml格式的文件,例如網絡安全配置文件network_security_config。
- Gradle構建配置文件build.gradle項目級構建配置build.gradle(Project: $project_name):用於配置適用於項目的Gradle構建設置,例如使用的Gradle版本,構建腳本的倉庫,依賴包倉庫。例如:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
//這裡放置項目構建倉庫
google()
jcenter()
}
dependencies {
//這裡放置項目構建所需的依賴,而不是模塊(總之平時用的依賴一般都不是放這裡)的依賴
classpath "com.android.tools.build:gradle:4.1.1"
// NOTE: Do not place your application dependencies here; they belong in the individual module build.gradle files
}
}
allprojects {
repositories {
//依賴包倉庫,也就是依賴包從哪下載,一般使用國內鏡像下載快很多
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}//阿里雲的倉庫,便於下載依賴包
maven{ url "https://jitpack.io"}
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}- 模塊級構建配置build.gradle(Module: $project_name.app)
…
dependencies {
//這裡才是放置要用到的第三方依賴的地方
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
implementation 'androidx.fragment:fragment:1.2.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.squareup.okhttp3:okhttp:3.10.0'//http通信的依賴庫
implementation 'com.github.bumptech.glide:glide:3.7.0'//加載圖像的依賴庫
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
implementation 'com.makeramen:roundedimageview:2.2.1'
implementation 'com.google.code.gson:gson:2.8.7'
}3.3 程序設計要點
3.3.1 Activity和Fragment的生命周期
正如生物一樣,Activity和Fragment作為安卓交互程序也有“生死”,也就是生命周期。
Activity生命周期:
如圖為一個Activity從被啟動到被停止的生命周期:
圖2 Activity生命周期[2]
- onCreate(): Ativity被創建的時候,常用於初始化基本布局,使用setContentView()加載布局文件,進行一些其它基本不耗時間的操作,實在需要就用異步線程,避免頁面長時間空白。
- onStart(): Activity被展示的時候,也就是說被創建了不一定要顯示出來,但要顯示出來了才onStart()。
- onPause(): Activity將要被掛起的時候,頁面失去焦點無法交互,此時Activity仍可見,比如將轉入後台運行。
- onResume():Activity已經從後台喚起並顯示出來,將要但還未獲得焦點無法操作的時候。
- onStop(): Activity以及失去焦點且要轉入後台的時候,此時Activity已不可見。
- onRestart(): Activity被掛起後又被喚醒的時候,此時Activity還未顯示出來。
- onDestroy(): Activity被徹底銷毀的時候。
Fragment生命周期:
Fragment生命周期與Activity周期較為類似,但其中比較值得提及的是:
- onAttach():Fragment與Activity建立關聯的時候,也就是此時Fragment已經知道了擁有自己的“上司”Activity是誰。
- onActivityCreated():此時建立關聯的Activity已經結束了onCreate()並返回。
- onCreateView():此時初始化Fragment布局,也是將基本的布局加載好,不建議耗時間的操作,實在需要就用異步線程。
- onDestroyView():Fragment的視圖已經被銷毀,但與Activity的關聯未銷毀,仍然可以重新創建視圖。
- onDetach():與Activity的關聯將要被解除,Activity在onDestory()時會自動調用與之有關聯的Fragment的onDetach()方法。
3.3.2 網絡請求與異步線程
Android 4.0以後網絡請求不能在主線程中執行已經是老生常談了,這是為例放置線程阻塞應用無響應。解決方案一般就是啟動異步線程進行處理,UI線程和網絡請求就分離開了,各干各的。但這之間如何通信呢,或者說網絡請求結束,不管成功失敗,如何告訴UI線程?這將在3.3.3 Handler消息處理中提到。
線程通常還要用到線程輔助類Runnable,在Runnable的要求強制重寫的方法run()中執行網絡請求任務。例如:
Runnable networkRunnable = new Runnable() {
@Override
public void run() {
//可以在此處執行網絡請求和數據解析操作,拉取聯繫人消息之類
}
};
Thread thread = new Thread(networkRunnable);
thread.start();//啟動線程不僅如此,耗時操作通常都是在線程中執行的,例如數據庫讀寫和一些其它文件操作之類,可見,多線程是安卓開發中一個重要的技術。
3.3.3 Handler和消息處理
上節中提到,不同線程間如何通信,Handler就是一個易用的方案。如果把各個線程比作各干各活的工人,Handler就像是個中間人,負責把各個工人傳來的消息進行處理,並有權操作UI線程中的組件,比如更新TextView的文字(非UI線程是不能操作的)。“工人”如何給Handler發一條消息?實現起來很簡單,比如網絡請求處理成功以後:
private final int NETWORK_PROCESS_OK = 1;//定義一個數字代號代表網絡處理成功
private final int NETWORK_PROCESS_FAIL = 0; //代表網絡處理失敗
Message msg = handler.obtainMessage();//需要保證此時Handler的實例handler已經實例化不為空。
msg.what= NETWORK_PROCESS_OK;
msg.sendToTarget();
//失敗以後也可以傳回原因:
Message msg = handler.obtainMessage();
msg.what= NETWORK_PROCESS_FAIL;
msg.obj=reason;//reason一般是String,但可以是任何Object
msg.sendToTarget();而Handler接收到消息後的處理一般如下:
handler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case NETWORK_PROCESS_OK:
textview.setText("處理成功!");
break;
case NETWORK_PROCESS_FAIL:
textview.setText("處理失敗!原因:" + msg.obj.toString());
break;
}
};
};3.3.4 Activity間的跳轉
Activity間使用Intent類進行跳轉和數據傳輸,具體如下:
Intent intent = new Intent(this,TargetActivity.class);//this是一個Activity對象
intent.putExtra(“param1”,paramString1);//通過intent傳送額外數據,可以在目標Activity中,使用getIntent()獲取傳入的intent對象,利用該intent對象的getStringExtra()接受傳入的String類型參數,當然也有其它類型的,此處不列舉。
startActivity(intent);值得注意的是,Intent所能傳輸的數據容量是有上限的,過多的數據不建議使用Intent進行傳輸。
3.3.5 回收型列表視圖RecyclerView的使用
RecyclerView是基於viewholder的回收理念在ListView上的一個升級版,功能強大,當然在不需要進行回收的場景就當然不要用了,例如實現多行可選擇的標籤,如果標籤滑出屏幕外被回收了的話,選中狀態也會一起丟失,除非用額外的對象進行選中狀態記錄。
RecyclerView的適用場景是有大量用於展示的列表數據的場景,比如微信的公眾號頁面的推文卡片、微信朋友圈、QQ的好友列表、小紅書的瀑布流帖子等。
和ListView類似,要將數據適配到視圖上進行展示需要使用適配器Adapter,不同的是RecyclerView的BaseAdapter已經將viewholder模式封裝好了,而目前RecyclerView的適配器有很多優秀的第三方庫,例如Github上開源的CymChad的適配器助手
BaseRecyclerViewAdapterHelper,封裝了基本的適配器操作,秩序簡短的幾行代碼就能實現基本的適配操作,也封裝了很多功能豐富的類與接口,例如可以實現下拉刷新,上拉加載的接口,可以實現多布局共存的MultiItemAdapter<T>等等[4],因此在合適的場景下使用是很好的,避免重複造輪子,但為了學習和了解更底層的原理,本項目中還是用最原始的ListView和RecyclerView的自帶適配器。
3.3.6 適配器理念Adapter
如上所說,列表視圖需要一個中間件:適配器,來將數據適配到布局上,這是一個從結構化的數據到結構化的視圖的中間過程,縱觀整個項目開發,可以發現有很多地方在使用這樣的理念,除了列表視圖的適配器以外,裝載Fragment的ViewPager的PagerAdapter也是同樣使用了適配器的概念,使得ViewPager可以比較方便的管理多個Fragment,降低耦合。同樣的,這樣的理念也可以運用到有着多種網絡請求的場景中,使用工廠模式和適配器理念,將網絡請求返回結果適配到實體類對象或UI視圖裡,這對於降低耦合度和提高多態性是很有幫助的。
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/268471.html
微信掃一掃
支付寶掃一掃