《阿里巴巴Android編碼規範》閱讀紀要(一)

版權聲明:本文出自汪磊的博客,轉載請務必註明出處。

2月28日阿里巴巴首次公開內部安卓編碼規範,試想那麼多業務線,開發人員,沒有一套規範管理起來是多麼麻煩,如下是我的閱讀Android基本組件部分過程當中以爲不錯的地方,摘錄下來。緩存

Android基本組件部分安全

1,Activity#onSaveInstanceState()方法不是Activity生命週期方法,也不保證必定會被調用。它是用來在Activity被意外銷燬時保存UI狀態的,只能用於保存臨時性數據,例如UI控件的屬性等,不能跟數據持久化存儲混爲一談。持久化存儲應該在Activity#onPause()/onStop()中實行。ide

2,Activity間經過隱式Intent的跳轉,在發出Intent以前必須經過resolveActivity檢查,避免找不到合適的調用組件形成ActivityNotFoundException的異常。如:post

 1 public void viewUrl(String url, String mimeType){
 2         
 3         Intent intent = new Intent(Intent.ACTION_VIEW);
 4         intent.setDataAndType(Uri.parse(url), mimeType);
 5         
 6         if(getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)!=null){
 7             
 8             try{
 9                 
10                 startActivity(intent);
11             }catch(ActivityNotFoundException e){
12                 
13             }    
14         }
15 }

3,避免使用隱式Intent廣播敏感信息,信息可能被其餘註冊了對應BroadcastReceiver的App接。動畫

說明:this

經過 Context#sendBroadcast()發送的隱式廣播會被全部感興趣的 receiver 接收,惡意應用註冊監聽該廣播的 receiver 可能會獲取到 Intent 中傳遞的敏感信息,並進行其餘危險操做。若是發送的廣播爲使用 Context#sendOrderedBroadcast()方法發送的有序廣播,優先級較高的惡意receiver 可能直接丟棄該廣播,形成服務不可用,或者向廣播結果塞入惡意數據。若是廣播僅限於應用內,則可使LocalBroadcastManager#sendBroadcast()實現,避免敏感信息外泄和 Intent 攔截的風險。編碼

如:url

1 Intent intent = new Intent("my-sensitive-event");
2 intent.putExtra("event", "this is a test event"); 
3 LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

4,不要在 Activity#onDestroy()內執行釋放資源的工做,例如一些工做線程的銷燬和中止,由於 onDestroy() 執行的時機可能較晚。可根據實際須要,在Activity#onPause()/onStop()中結合 isFinishing()的判斷來執行。spa

5,如非必須,避免使用嵌套的 Fragment。線程

說明:

嵌套 Fragment 是在 Android API 17 添加到 SDK 以及 Support 庫中的功能,

Fragment 嵌套使用會有一些坑,容易出現 bug,比較常見的問題有以下幾種:

1)onActivityResult()方法的處理錯亂,內嵌的 Fragment 可能收不到該方法的回調,須要由宿主 Fragment 進行轉發處理;

2)突變更畫效果;

3)被繼承的 setRetainInstance(),致使在 Fragment 重建時屢次觸發沒必要要的邏輯。

非必須的場景儘量避免使用嵌套 Fragment,如需使用請注意上述問題。

正例:

 1 FragmentManager fragmentManager = getFragmentManager();
 2 Fragment fragment =fragmentManager.findFragmentByTag(FragmentB.TAG);
 3 if (null == fragment) {
 4     FragmentB fragmentB = new FragmentB();
 5 
 6     FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
 7 
 8   fragmentTransaction.add(R.id.fragment_container, fragmentB, FragmentB.TAG).commit();
 9 
10 
11 }
12     

反例:

1 Fragment videoFragment = new VideoPlayerFragment();
2 
3 FragmentTransaction transaction = currentFragment.getChildFragmentManager().beginTransaction();
4 
5 transaction.add(R.id.video_fragment, videoFragment).commit();

6,對於只用於應用內的廣播,優先使用 LocalBroadcastManager 來進行註冊和發送,LocalBroadcastManager 安全性更好,同時擁有更高的運行效率。

說明:

對於使用 Context#sendBroadcast()等方法發送全局廣播的代碼進行提示。若是該廣播僅用於應用內,則可使用 LocalBroadcastManager 來避免廣播泄漏以及廣播被攔截等安全問題,同時相對全局廣播本地廣播的更高效。

7,當前 Activity 的 onPause 方法執行結束後纔會執行下一個 Activity 的 onCreate 方法,因此在 onPause 方法中不適合作耗時較長的工做,這會影響到頁面之間的跳轉效率。

8,不要在 Android 的 Application 對象中緩存數據。基礎組件之間的數據共享請使用 Intent 等機制,也可以使用 SharedPreferences 等數據持久化機制。

9,使用 Adapter 的時候,若是你使用了 ViewHolder 作緩存,在 getView()的方法中不管這項 convertView 的每一個子控件是否須要設置屬性(好比某個 TextView 設置的文本可能爲 null,某個按鈕的背景色爲透明,某控件的顏色爲透明等),都須要爲其顯式設置屬性(Textview 的文本爲空也須要設置 setText(""),背景透明也須要設置),不然在滑動的過程當中,由於 adapter item 複用的緣由,會出現內容的顯示錯亂。

正例:

 1     @Override
 2     public View getView(int position, View convertView, ViewGroup parent) {
 3         ViewHolder myViews;
 4 
 5         if (convertView == null) {
 6 
 7             myViews = new ViewHolder();
 8 
 9             convertView = mInflater.inflate(R.layout.list_item, null);
10 
11             myViews.mUsername = (TextView) convertView
12                     .findViewById(R.id.username);
13             convertView.setTag(myViews);
14         } else {
15 
16             myViews = (ViewHolder) convertView.getTag();
17 
18         }
19 
20         Info p = infoList.get(position);
21 
22         String dn = p.getDisplayName;
23 
24         myViews.mUsername.setText(StringUtils.isEmpty(dn) ? "" : dn);
25         return convertView;
26 
27     }
28 
29     static class ViewHolder {
30 
31         private TextView mUsername;
32 
33     }

10,Activity 或者 Fragment 中動態註冊 BroadCastReceiver 時,registerReceiver()和 unregisterReceiver()要成對出現。

說明:

若是 registerReceiver()和 unregisterReceiver()不成對出現,則可能致使已經註冊的

receiver 沒有在合適的時機註銷,致使內存泄漏,佔用內存空間,加劇 SystemService 負擔。

部分華爲的機型會對 receiver 進行資源管控,單個應用註冊過多 receiver 會觸發管控模塊拋出異常,應用直接崩潰。

正例:

 1 public class MainActivity extends AppCompatActivity {
 2 
 3         private static MyReceiver myReceiver = new MyReceiver();
 4 
 5         @Override
 6         protected void onResume() {
 7             super.onResume();
 8             IntentFilter filter = new IntentFilter("com.example.myservice"); 
 9             registerReceiver(myReceiver, filter);
10         }
11 
12         @Override
13         protected void onPause() {
14             super.onPause();
15             unregisterReceiver(myReceiver);
16         }
17 }

反例:

 1 public class MainActivity extends AppCompatActivity {
 2         
 3         private static MyReceiver myReceiver; 
 4         
 5         @Override
 6         protected void onResume() {
 7             super.onResume();
 8             myReceiver = new MyReceiver();
 9             IntentFilter filter = new IntentFilter("com.example.myservice"); 
10             registerReceiver(myReceiver, filter);
11         }
12 
13         @Override
14         protected void onDestroy() {
15             super.onDestroy();
16             unregisterReceiver(myReceiver);
17         }
18 }

Activity 的生命週期不對應,可能出現屢次 onResume 形成 receiver 註冊多個,但最終只註銷一個,其他 receiver 產生內存泄漏。

以上就是阿里巴巴安卓編碼規範中Android基本組件部分說起的一些規範,並無所有列出來,只是記錄一些我的以爲不錯的地方,總體下來感受都是細微的地方,感興趣的同窗能夠自行查找完整版《阿里巴巴Android編碼規範》閱讀一下,裏面仍是有點乾貨的。

好了,本篇到此結束,但願對你有用。

相關文章
相關標籤/搜索