• 《阿里巴巴Android编码规范》阅读纪要(一)


    版权声明:本文出自汪磊的博客,转载请务必注明出处。

    2月28日阿里巴巴首次公开内部安卓编码规范,试想那么多业务线,开发人员,没有一套规范管理起来是多么麻烦,以下是个人阅读Android基本组件部分过程中觉得不错的地方,摘录下来。

    Android基本组件部分

    1,Activity#onSaveInstanceState()方法不是Activity生命周期方法,也不保证一定会被调用。它是用来在Activity被意外销毁时保存UI状态的,只能用于保存临时性数据,例如UI控件的属性等,不能跟数据持久化存储混为一谈。持久化存储应该在Activity#onPause()/onStop()中实行。

    2,Activity间通过隐式Intent的跳转,在发出Intent之前必须通过resolveActivity检查,避免找不到合适的调用组件造成ActivityNotFoundException的异常。如:

     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接。

    说明:

    通过 Context#sendBroadcast()发送的隐式广播会被所有感兴趣的 receiver 接收,恶意应用注册监听该广播的 receiver 可能会获取到 Intent 中传递的敏感信息,并进行其他危险操作。如果发送的广播为使用 Context#sendOrderedBroadcast()方法发送的有序广播,优先级较高的恶意receiver 可能直接丢弃该广播,造成服务不可用,或者向广播结果塞入恶意数据。如果广播仅限于应用内,则可以使LocalBroadcastManager#sendBroadcast()实现,避免敏感信息外泄和 Intent 拦截的风险。

    如:

    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()的判断来执行。

    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编码规范》阅读一下,里面还是有点干货的。

    好了,本篇到此结束,希望对你有用。

  • 相关阅读:
    C#总结(四)调用C++动态库
    Golang 入门系列(十二)ORM框架gorm
    《关键对话》如何高效沟通,营造无往不利的事业和人生?
    Golang 入门系列(十一)Go语言实现webapi
    Golang 入门系列(十) mysql数据库的使用
    Golang 入门系列(九) 如何读取YAML,JSON,INI等配置文件
    Golang 入门系列(八) cron定时任务
    Golang 入门系列(七) Redis的使用
    福利 | 互联网产品经理学习资料免费下载(可下载)
    福利 | 2018各大技术大会资料汇总(可下载)
  • 原文地址:https://www.cnblogs.com/leipDao/p/8566723.html
Copyright © 2020-2023  润新知