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編碼規範》閱讀一下,裏面仍是有點乾貨的。
好了,本篇到此結束,但願對你有用。