用最优雅的方式startActivity

来源:互联网 发布:gis基础软件平台 编辑:程序博客网 时间:2024/06/07 03:58

写在前面

相信很多人看到标题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.javaTestActivity.startTargetActivity(this,age,name);

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

创建Intent对象,putExtra等模板代码还是免不了。参数不多还好,假如参数多了呢?
用Intent#getXxxExtra从Intent中逐个取出参数,这样的代码也是免不了,而且还是得关注每个参数的key。
假如参数一多,启动Activity的静态方法的参数列表就变得会非常长。一大串参数,看着就不舒服。
对于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();

原理

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

在代码编译时,会有一个注解处理器,负责解析被注解标注的Element的信息,比如这里我需要获取字段名作为key,和字段类型,所以就用@IntentValue标注,在编译时这些被标注的字段会交给注解处理器来处理。而我们的工作就是编写注解处理器,解析并收集这些字段信息,生成相关辅助代码。生成的代码可以在build目录中找到:
这里写图片描述
此外,AutoGo这个项目还支持更优雅地使用SharedPreference和Bundle来存储数据。喜欢不妨点个star :)

项目源码—Github : https://github.com/TellH/AutoGo

原创粉丝点击