1. 程式人生 > >Android開發規範以及注意事項

Android開發規範以及注意事項

一、Android資原始檔命名與使用 

1.【推薦】資原始檔需要帶模組字首。

2.【推薦】layout檔案的命名方式。

Activity的layout以module_activity開頭

Fragment的laytout以module_fragment開頭

ListView的layout以modlue_lits_item開關等

3.【推薦】

 drawable 資源名稱以小寫單詞+下劃線的方式命名,根據解析度不同存放 在不同的 drawable 目錄下,建議只使用一套,例如 drawable-xhdpi。採用規則如下: 

模組名_業務功能描述_控制元件描述_控制元件狀態限定詞 

如:module_login_btn_pressed,module_tabs_icon_home_normal 

4.【推薦】anim 資源名稱以小寫單詞+下劃線的方式命名,採用以下規則: 
模組名_邏輯名稱_[方向|序號] 
tween 動畫資源:儘可能以通用的動畫名稱命名,如 module_fade_in , module_fade_out , module_push_down_in (動畫+方向); 
frame 動畫資源:儘可能以模 塊+功能命名+序號。如:module_loading_grey_001 

5. 【推薦】 color 資源使用#AARRGGBB 格式,寫入 module_colors.xml 檔案中,命 名格式採用以下規則: 
模組名_邏輯名稱_顏色 
如: 
<color name="module_btn_bg_color">#33b5e5e5</color> 

6. 【推薦】dimen 資源以小寫單詞+下劃線方式命名,寫入 module_dimens.xml 檔案中, 採用以下規則: 
模組名_描述資訊 
如: 
<dimen name="module_horizontal_line_height">1dp</dimen> 
7. 【推薦】style 資源採用小寫單詞+下劃線方式命名,寫入 module_styles.xml 檔案中, 採用以下規則: 
父 style 名稱.當前 style 名稱 
如: 
<style name="ParentTheme.ThisActivityTheme"> 
    … 
</style> 
8. 【推薦】 string資原始檔或者文字用到字元需要全部寫入module_strings.xml檔案中, 字串以小寫單詞+下劃線的方式命名,採用以下規則:
 
模組名_邏輯名稱 
如:moudule_login_tips,module_homepage_notice_desc 
9. 【推薦】Id 資源原則上以駝峰法命名,View 元件的資源 id 需要以 View 的縮寫作為 字首。常用縮寫表如下: 
控制元件 縮寫 
LinearLayout ll RelativeLayout rl ConstraintLayout cl ListView lv ScollView sv TextView tv Button btn ImageView iv CheckBox cb RadioButton rb EditText et 


10.【推薦】大解析度圖片(單維度超過 1000)大解析度圖片建議統一放在 xxhdpi 目錄 下管理,否則將導致佔用記憶體成倍數增加。 

說明: 
為了支援多種螢幕尺寸和密度,Android 為多種螢幕提供不同的資源目錄進行適配。 為不同螢幕密度提供不同的點陣圖可繪製物件,可用於密度特定資源的配置限定符(在 下面詳述) 包括 ldpi(低)、mdpi(中)、 hdpi(高)、xhdpi(超高)、xxhdpi (超 超高)和 xxxhdpi(超超超高)。例如,高密度螢幕的點陣圖應使用 drawable-hdpi/。
 
根據當前的裝置螢幕尺寸和密度,將會尋找最匹配的資源,如果將高解析度圖片放 入低密度目錄,將會造成低端機載入過大圖片資源,又可能造成 OOM,同時也是資 源浪費,沒有必要在低端機使用大圖。 


正例: 
將 144*144 的應用圖示 PNG 檔案放在 drawable-xxhdpi 目錄 
反例: 
將 144*144 的應用圖示 PNG 檔案放在 drawable-mhdpi 目錄 

二、Android的基本元件

Android的基本元件指Activity、Fragment、Service、BroadCastReceiver、ContentProvider等

1.【強制】Activity間的資料通訊,對於資料量比較大的,避免使用Intent+Parcelable的方式,可以考慮EventBus等替代方案,以免造成TransactionToolargeException.

2.【推薦】Activity#onSaveInstanceState()方法不是Activity生命週期方法,也不保證一定會被呼叫,例如UI控制元件的屬性等,不能跟資料的持久化儲存混為一談,持久化儲存應該

在Activity#onPause()/onStop()中實行。

3.【強制】Activity間通過隱式Intent的跳轉,在發出Intent之前必須通過resolveActivity檢查,避免找不到合適 的呼叫元件,造成ActivityNotFoundException異常。

正例: 
public void viewUrl(String url, String mimeType) { 
    Intent intent = new Intent(Intent.ACTION_VIEW); 
   intent.setDataAndType(Uri.parse(url), mimeType); 
   if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ ONLY) != null) { 
        try { 
       startActivity(intent); 
       } catch (ActivityNotFoundException e) { 
            if (Config.LOGD) { 
               Log.d(LOGTAG, "activity not found for " + mimeType + " over " + Uri.parse(url). getScheme(), e); 
            } 
        } 
    } 

反例: 
Intent intent = new Intent(); 
intent.setAction("com.great.activity_intent.Intent_Demo1_Result3"); 

4.【強制】避免在Service#onStartCommand()/onBind()方法中執行耗時操作,如果確實有需求,應該用IntentSevice或採用其他非同步機制完成。

正例:
public class MainActivity extends Activity {
    @Override
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    public void startIntentService(View source) {
        Intent intent = new Intent(this, MyIntentService.class);
        startService(intent);
    }
}
public class MyIntentService extends IntentService {
    public MyIntentService() {
        super("MyIntentService");
    }
    @Override
protected void onHandleIntent(Intent intent) {
        synchronized (this) {
            try {
            ......
            } catch (Exception e) {
            } 正例:
            public class MainActivity extends Activity {
                @Override
public void onCreate(Bundle savedInstanceState) {
                    super.onCreate(savedInstanceState);
                    setContentView(R.layout.main);
                }

                public void startIntentService(View source) {
                    Intent intent = new Intent(this, MyIntentService.class);
                    startService(intent);
                }
            }
            public class MyIntentService extends IntentService {
                public MyIntentService() {
                    super("MyIntentService");
                }

                @Override
protected void onHandleIntent(Intent intent) {
                    synchronized (this) {
                        try {
            ......
                        } catch (Exception e) {
                        }


                    }
                }
            }

5.【強制】避免在BroadcastReceiver#onReceiver()中執行耗時操作,如果有耗時工作,應該建立IntentService完成,而不應該在BroadCastReceiver內建立子執行緒去做。

說明:

由於該方法是在主執行緒執行,如果執行耗時操作會導致Ui不流暢。可以使用IntentService、建立HandlerThread或者呼叫Context#registerReceiver方法等方式 ,在其他 Worker執行緒執行onReceiver方法。BroadCastReceiver#onRecive()方法耗時超過10秒鐘,可能會被系統殺死。

正例: 
IntentFilter filter = new IntentFilter(); 
filter.addAction(LOGIN_SUCCESS); 
this.registerReceiver(mBroadcastReceiver, filter);  
mBroadcastReceiver = new BroadcastReceiver() { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
        Intent userHomeIntent = new Intent(); 
        userHomeIntent.setClass(this, UseHomeActivity.class); 
        this.startActivity(userHomeIntent); 
    } 
}; 

反例: 
mBroadcastReceiver = new BroadcastReceiver() { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
       MyDatabaseHelper myDB = new MyDatabaseHelper(context); 
       myDB.initData(); 
       // have more database operation here 
    } 
}; 

8. 【推薦】不要在 Activity#onDestroy()內執行釋放資源的工作,例如一些工作執行緒的 銷燬和停止,因為 onDestroy()執行的時機可能較晚。可根據實際需要,在 Activity#onPause()/onStop()中結合 isFinishing()的判斷來執行。 

9. 【推薦】如非必須,避免使用巢狀的 Fragment。 
說明: 
巢狀 Fragment 是在 Android API 17 新增到 SDK 以及 Support 庫中的功能, Fragment 巢狀使用會有一些坑,容易出現 bug,比較常見的問題有如下幾種: 
1) onActivityResult()方法的處理錯亂,內嵌的 Fragment 可能收不到該方法的回撥, 需要由宿主 Fragment 進行轉發處理; 
2) 突變動畫效果; 
3) 被繼承的 setRetainInstance(),導致在 Fragment 重建時多次觸發不必要的邏 輯。 
非必須的場景儘可能避免使用巢狀 Fragment,如需使用請注意上述問題。 

10.【推薦】總是使用顯式Intent啟動或者繫結Service,且不要為服務宣告IntentFilter,保證應用的安全性。如果確實需要 使用隱式呼叫,則可為Service提供IntentFilter並從Intent中排除相應的元件名稱,但必須搭配使用Intent#setPackage()方法設定Intent的指定包名,這樣可以充分消除目標服務的不確定性。

11【推薦】Service需要以多執行緒來併發處理多個啟動請求,建議使用IntentService,可避免各種複雜的設定。

說明:

Service元件一般執行主執行緒,應該避免耗時操作,如果有耗時操作應該在Worker執行緒執行。可以使用IntentService執行後臺任務。

12.【推薦】當前Activity的onPause方法執行結束後才會執行下一個Activity的onCreate 方法,所以在 onPause 方法中不適合做耗時較長的工作,這會影響到頁面之間的跳 轉效率。 

13.【強制】不要在 Android 的 Application 物件中快取資料。基礎元件之間的資料共享 請使用 Intent 等機制,也可使用 SharedPreferences 等資料持久化機制。 

14.【推薦】使用 Toast 時,建議定義一個全域性的 Toast 物件,這樣可以避免連續顯示 Toast 時不能取消上一次 Toast 訊息的情況(如果你有連續彈出 Toast 的情況,避免 使用 Toast.makeText)。 

15. 【強制】使用 Adapter 的時候,如果你使用了 ViewHolder 做快取,在 getView()的 方法中無論這項 convertView 的每個子控制元件是否需要設定屬性(比如某個 TextView 設定的文字可能為 null,某個按鈕的背景色為透明,某控制元件的顏色為透明等),都需 要為其顯式設定屬性(Textview的文字為空也需要設定 setText(""),背景透明也需要 設定),否則在滑動的過程中,因為 adapter item 複用的原因,會出現內容的顯示錯 亂。 

16.【強制】Activity或者Fragment中動態註冊BroadCastReceiver時,registerReceiver() 和 unregisterReceiver()要成對出現。 

說明: 
如果 registerReceiver()和 unregisterReceiver()不成對出現,則可能導致已經註冊的 receiver沒有在合適的時機登出,導致記憶體洩漏,佔用記憶體空間,加重SystemService 負擔。 
部分華為的機型會對 receiver 進行資源管控,單個應用註冊過多 receiver 會觸發管 控模組丟擲異常,應用直接崩潰。