用最优雅的方式startActivity

Posted TellH

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用最优雅的方式startActivity相关的知识,希望对你有一定的参考价值。

写在前面

相信很多人看到标题startActivity可能会轻蔑一笑,启动Activity不是android开发里基础得不能再基础的内容吗? 但相信点进来的各位看官都是追求优雅编码的开发者:) 。我要用一个优雅的姿势,最小的代码来启动一个Activity。

startActivity的原生式

启动Activity原生方式是new 一个Intent,将需要传递的参数put进Intent,再调用Activity#startActivity:

        Intent intent = new Intent(this, TestActivity.class);
        intent.putExtra("age", age);
        intent.putExtra("name", name);
        startActivity(intent);

startActivity的改进式

在开发当中,往往需要知道TargetActivity要接收的参数有哪些,难道我们每次启动TargetActivity都要打开TargetActivity.java看看它需要哪些参数,而且在TargetActivity取出参数的时候还得记住每一参数的key? 为什么不让厨师列一份食材清单,而不是每次需要炒菜时都去问厨师需要什么食材呢。聪明的开发者想到了在TargetActivity加一个静态方法,将启动Activity的工作都放到这个方法中。

////------TargetActivity.java
    public static void startTargetActivity(Activity srcActivity, int age, String name) 
        Intent intent = new Intent(srcActivity, TestActivity.class);
        intent.putExtra("age", age);
        intent.putExtra("name", name);
        srcActivity.startActivity(intent);
    
////-------SrcActivity.java
TestActivity.startTargetActivity(this,age,name);

这样启动Activity的控制权就交由TargetActivity,这样的确省了不少重复的代码。然而故事并没有结束,这种方式仍有不少痛点。

  1. 创建Intent对象,putExtra等模板代码还是免不了。参数不多还好,假如参数多了呢?
  2. 用Intent#getXxxExtra从Intent中逐个取出参数,这样的代码也是免不了,而且还是得关注每个参数的key。
  3. 假如参数一多,启动Activity的静态方法的参数列表就变得会非常长。一大串参数,看着就不舒服。
  4. 对于startActivity的调用方来说,假如有些参数它不想传,那就只能传一个null。就像这样,迷之传null:(
TestActivity.startTargetActivity(this,null,null,null,null,null);

为了解决上述痛点,以下优雅式应运而生。

startActivity的优雅式

既然一次调用需要参数灵活,又不想写一大堆重载函数,我们想到用建造者模式。就像RxJava那样的链式调用就是我们需要的:

XXX.from(MainActivity.this)
                .gotoTargetActivity()
                .age(18)
                .name("tlh")
                .go();

为了实现这种优雅调用,我受dagger和butterKnift的启发写了一个基于编译时注解的开源库AutoGo
具体用法:

  • 在目标Activity(以下简称TargetActivity)的字段用@IntentValue标注,注解参数将作为传进Intent的key,如果不传,字段名将作为key。调用AutoGo.assign(activity);就可以自动为被@IntentValue标注的字段赋值。
    标注好后最好Make Project(Ctrl+F9),编译一下代码,以产生辅助代码。
public class TargetActivity extends AppCompatActivity 
    //the annotated field should not be private
    @IntentValue("myName") String name;
    @IntentValue int age;
    ......
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        AutoGo.assign(this);
  • 在调用方用链式调用的方式传参,启动Activity。
        AutoGo.from(SrcActivity.this)
                .gotoTargetActivity()
                .age(18)
                .myName("tlh")
                .go();

这样,短短几行代码,把启动Activity的动作变得如此优雅,pretty awesome。

原理

有朋友可能会问,这货使用注解会影响性能的吧? 放心,请不要谈注解色变。注解大概分成两种,一种是运行时注解,也就是在运行时起作用,因为在运行时需要通过反射获取被注解Element(如字段,类,方法)的信息,会有一定的性能影响;一种是编译期注解,这种注解一般是不会在添加到class文件的,对代码性能几乎没有影响,熟知的dagger,butterKnife,greenDao就是基于编译期注解。

在代码编译时,会有一个注解处理器,负责解析被注解标注的Element的信息,比如这里我需要获取字段名作为key,和字段类型,所以就用@IntentValue标注,在编译时这些被标注的字段会交给注解处理器来处理。而我们的工作就是编写注解处理器,解析并收集这些字段信息,生成相关辅助代码。生成的代码可以在build目录中找到:

此外,AutoGo这个项目还支持更优雅地使用SharedPreference和Bundle来存储数据。喜欢不妨点个star :)

项目源码—Github

以上是关于用最优雅的方式startActivity的主要内容,如果未能解决你的问题,请参考以下文章

iOS开发进阶-用最简单的方式自定义TabBar

如何优雅地在LaTeX中使用中文?

如何判断架构设计的优雅和优劣

报告 data.frame 中缺失值的优雅方式

java优雅的使用elasticsearch

在 Ruby 中找到第一个可能匹配的哈希键的优雅方式