原来Activity跳转还可以这么舒畅

原创博客,如有转载,请注明出处,非常感谢。

(前置说明,我这里所说的POJO,就是大家认为的POJO去掉了getter/setter)
这里给大家带来的是一个开源项目,托管在github上的:SmartKey,喜欢的同学请给个星星鼓励一下,非常感谢。祝愿大家写代码写得越来越舒畅,下班越来越准时。

在开源世界索取了这么多年,终于第一次往开源界添点小小的砖瓦,甭提有多高兴了,先预览一下demo代码感受一下,你见过这样startActivity的吗?不写key,不写Intent,不写putExtra,不写XXXActivity.class;不写key,不写Intent,不写putExtra,不写XXXActivity.class;不写key,不写Intent,不写putExtra,不写XXXActivity.class;重要的事情我要说三遍,别拦我:

我有一个Activity,名字叫ForResultActivity,跳转到他的时候是这样调用的:

// Demo on how to elegantly passing and receiving extras with intent.
SmartTargets.toForResultActivityATarget()
        .params(ForResultReqIBuilder
                .newBuilder()
                .title(App.getStr(R.string.input_something))
                .label(App.getStr(R.string.this_is_label))
                .hint(App.getStr(R.string.this_is_hint)))
        .goForResult(activity, REQ_CODE_FOR_RESULT);

在目标ForResultActivity里获取传过来的参数(其实是ForResultVM类里,因为Demo里用了最简单原始的MVVM模式)

// Getting values in this very easy way
ForResultReq req = ForResultReqIBuilder.getSmart(activity.getIntent());

** 套路就是SmartTargets出发,to目标,带参数,走起!一个链条一气呵成。 **
以上代码里,SmartTargets类是自动生成的,ForResultReqIBuilder类也是自动生成的!!!你只需要关注你的业务数据,参数究竟怎么放进Intent 的,Intent是哪里创建的,extras的key怎么管理的,目标Activity的class什么时候放进Intent的,或者action,category什么时候放进Intent的,extras取出来又是怎么取的,有完没完啊,这么多问题!!!好了,在这里,这些东西通通不需要关注,真的,你只需要关注你的业务数据,并且,对于已有的代码已有的key管理,你可以保留,这个库直接与原有代码兼容,无痛升级有木有!

好了,啰嗦了这么久,咱们详细说说这个SmartKey吧,首先得从我们最初是怎么进行Activity跳转说起,先讲点历史,忆苦思甜嘛,必须的。相信大家一定走过类似的路。
皇上,您还记得那年大明湖畔的夏雨荷吗?哦,不好意思,大家还记得最初学Android开发的时候怎么启动一个新的Activity吗?来,上代码:

Intent in = new Intent(this, ForResultActivity.class);
in.putExtra("title", App.getStr(R.string.input_something));
in.putExtra("label", App.getStr(R.string.this_is_label));
in.putExtra("hint", App.getStr(R.string.this_is_hint));
startActivityForResult(in, REQ_CODE_FOR_RESULT);

大家还想回到那个年代么?那个年代我想回,但是我不想再写这样的代码了
putExtra这样的模板代码能不能不写?
extra的key能不能不写?看到这样的“Magic Number/String”我就发毛,香菇,蓝瘦。
就算写,这些key从哪里找阿?每次去目标Activity翻么?万一我拷贝的时候拷漏了一个字母怎么办?好害怕啊。我真试过一个"nickName"和"nickname"这样的拼写问题,浪费了不少时间,不要笑,说的就是你。
于是来了第一个升级版(putExtra还是写,毕竟通过Intent传参你只有这么一条路可走):
在ForResultActivity的最头部,我写了以下的代码:

public static final String EXTRA_TITLE = "title";
public static final String EXTRA_LABEL = "label";
public static final String EXTRA_HINT = "hint";

然后启动ForResultActivity的时候变成了:

Intent in = new Intent(this, ForResultActivity.class);
in.putExtra(ForResultActivity.EXTRA_TITLE, App.getStr(R.string.input_something));
in.putExtra(ForResultActivity.EXTRA_LABEL, App.getStr(R.string.this_is_label));
in.putExtra(ForResultActivity.EXTRA_HINT, App.getStr(R.string.this_is_hint));
startActivityForResult(in, REQ_CODE_FOR_RESULT);

拼写错误问题解决了,随着项目的扩大,问题又来了,我在MyActivity,YourActivity,HisActivity等等几个Activity都用到同样的key,我每个Activity都抄一次public static final String EXTRA_XXX吗?相信没谁这么笨的。还有,有些activity的启动是通过action的,天啊,这些通过action跳转的隐式Intent传参key应该放哪里?于是,又一个升级版,这次是集中管理extra的key:

public class MyExtraKeys {
    public static final String EXTRA_TITLE = "title";
    public static final String EXTRA_LABEL = "label";
    public static final String EXTRA_HINT = "hint";
    // 更多省略
}

key的问题解决的差不多了,隐式action的问题,这个也好解决,参照前面的MyExtraKeys的做法,我写了一个MyActionUtils类,因为跟上面接近,就不复述了,无非是通过一个相对友好的,容易调用的字段对应到action。
下一步,我相信是很多高级点的工程师喜欢的做法,就是把跳转的方法定义成一个静态的方法,并且把参数组装都放在目标Activity上面,有多种方法的时候,写多个类似的方法:

public static void toForResultActivity(Context from, String title, String label, String hint) {
    Intent in = new Intent(from, ForResultActivity.class);
    in.putExtra(MyExtraKeys.EXTRA_TITLE, title);
    in.putExtra(MyExtraKeys.EXTRA_LABEL, label);
    in.putExtra(MyExtraKeys.EXTRA_HINT, hint);
    if(!(from instanceof Activity)) {
        in.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    }
    from.startActivity(in);
}
// 如果还有其他,继续写

一般情况,到这一步,大家也就满意了,然而,对于我,我还是觉得我高兴的太早,因为我的项目终于大到一定程度了,并且也不止我一个人写,由于经过一段时间的积累,也由于对队友的约束不严,技术也在变化,刚才解决的是参数传进来问题,但是还是有各种取出的方法散落在各处,这个时候哪怕一丁点的改动,都需要小心翼翼,什么时候掉进自己挖的坑被埋了都不清楚,于是重构提上日程,既然这些传来传去的参数已经散落在了各自发挥作用的角落,我能不能先把他们集中起来作为重构的第一阶段呢?
于是,有一个升级版的参数传递方案出来了,把参数打包起来传递:

public class ForResultExtras implements Parcelable {
    private String title;
    private String label;
    private String hint;
    
    // getters and setters ...
    // Parcelable implementation methods ...
}

这种方式使用就统一了,不再有那么多的key了,因为都是一个类传过来,每个组件都只接收一个自定义的参数,于是MyConstants里面关于参数的key只剩下了:

        public static final String EXTRA_KEY = "extra"; // 作为最通用的了

然而,这个方案有天生的问题,既然取出参数的方法原来已经散落各处了,现在要集中起来容易么?特别是我得写多少个类似的Parcelable框架性代码的实现啊?每个集中的类都必须写网parcel里写数据和读数据的方法,还几乎一样的,还要读写顺序一致。当然了,这些都是小问题了,github上搜索一下parceler你就知道了,有人帮你写好了包装,你只要写POJO就行,剩余的框架代码就不需要操心了。然而,集中起来这个问题没办法解决啊,与framework组件、第三方组件不能改的代码怎么打交道啊?这个方案还没真正使用一次,就直接被毙掉了,难道就无解了么?不可能!!!但是自己做之前是不是问问哑巴有没有什么好方案先呢?还真给我找到了一个非常不错的方案:
就是这个文章:用最优雅的方式startActivity
具体就不列出来了,大家自己点开看看,学习一下,人家写的很好,当然,如果他的方案真的解决了我的问题,那么就没有这篇文章了,我写这篇文章是因为他的方案并不能完成我需要解决的问题而已,不是说他写的不好,相反,我觉得相当好也给我不少启发,我的写的方案SmartKey也多少受到他的一些影响,当然,跟他的方案可以说完全不同,先说说为我用上面那个文章说的AutoGo的经验吧,这个库第一眼看到我就眼前一亮,以为终于找到完美的解决方案了,然后翻看源码,不错,着手引入到我的项目里,好了,不到三个钟,我发现很多跟我项目八字不合的问题了,简单说来解决不了的问题有以下,改成疑问的语气来写吧:

  1. 我原有的代码怎么办?我已经有上百个activity了,与原有方式能共存么?也就是说,我有些extra的获取是散落在各处的,一下子要集中并且取到字段里不容易,由于项目紧,一下子抽不出时间全改怎么办?其实时间是借口,主要问题是原逻辑非常复杂,贸然修改风险大,能缓一下,新写的跳转进来的代码用新的方式写,但是目标activity不改动行么?这个问题没解决。
  2. 跳转到安卓framework提供的组件,或者第三方库提供的组件,他们的key我改不了,他们的类也是现成的,所以也生成不了方法链,怎么办?这个问题没解决。
  3. 有些activity我需要用action来跳转,但我也想要用这个便利的方法链该怎么办?一样解决不了,因为他的注解需要写在目标Activity上,用action本来就是为了不明确知道目标Activity的隐式情况的。
  4. 有些activity的跳转,事先是不知道activity类名的,是根据服务器返回或其他配置值定的,我还是想用这个方法链怎么办?还是没有解决方法,因为跳转链条的开头就在目标Activity。
  5. AutoGo有代管SharedPreferences的方法,但是不灵活,每个字段必须要注解,并且调用AutoGo.save和AutoGo.restore方法的时候,对应对象的所有被托管的SharedPreferences都会被保存或者获取,我能只保存更改了的那个么?或者只获取我想要的那个么?毕竟多余的执行都是浪费资源啊。其实Intent也有同样的问题,需要把全部用到的需要传递字段注解,并且基本上几个Activity有同样参数的时候,必须写几份,也就是说写的代码不能复用。
  6. 因为SharedPreferences并没有集中管理,散落在各个使用的角落,key重复了怎么办?有方法自动检测出来么?答案是没办法知道,因为谁也不知道你的key重复是场景需要还是错误。

好吧,自己试试能不能造个轮子,这个轮子需要解决以上所有问题,并且至少要和AutoGo一样用的顺畅,不但Activity的跳转,SharedPreferences的问题也要一并解决了。
于是针对上面的问题,撸起袖子Code,先提前说一说SmartKey的使用套路:
SmartTargets开始,然后调用to目标Activity/Service,然后调用params方法放参数,这个params方法使用的参数类是自动生成的IBuilder类,方法链式调用非常舒畅,然后调用对应的go、goForResult、goWithAction方法或者start方法或者bind方法结尾,整个过程一条链,一气呵成。

  1. 另外设计一个入口,不再依赖目标Activity上面做改动,这样就避免了改动时必须在跳转开始和目标上都同时要做的问题了,那么,另外的入口通过什么东西来生成比较方便呢?AndroidManifest文件是所有Activity都需要在这里注册的,好,我就从这里入手去生成对应的跳转代码!然后对于extra的问题,我另外用一个POJO来处理这个问题,看代码:
@SmartManifest(manifestPath = "app/src/main/AndroidManifest.xml")
public class App extends Application {
    // App的其他代码,
}

根据上面代码,我可以生成一个SmartTargets的类,里面有所有Activity和Service的入口,每当要跳转或者启动Service的时候,就从SmartTargets出发,一直点到目标,另外,再设计了两个toNotDeterminedActivityTarget和toNotDeterminedServiceTarget方法给SmartTargets类,这样,无论怎样的Activity和Service都可以过去了。
对于POJO,以一直作为例子的ForResultActivity为例,我写了两个,一个是为了请求过来的时候传递参数的,一个是为了onActivityResult用的,两个类代码如下:

@SmartIntent
public class ForResultReq {
    public String title;
    public String label;
    public String hint;
}
@SmartIntent
public class ForResultRes {
    public String input;
    public String input2;
}

然后根据这两个类,APT工具自动生成两个对应的类,ForResultReqIBuilder和ForResultResIBuilder,使用方式就简单了,注意到两个类的注解么?对,只要加上这样的注解,代码就会自动生成,跳转代码(重复一次开头那段代码,_):

SmartTargets.toForResultActivityATarget()
        .params(ForResultReqIBuilder
                .newBuilder()
                .title(App.getStr(R.string.input_something))
                .label(App.getStr(R.string.this_is_label))
                .hint(App.getStr(R.string.this_is_hint)))
        .goForResult(activity, REQ_CODE_FOR_RESULT);

接收参数代码:

ForResultReq req = ForResultReqIBuilder.getSmart(activity.getIntent());

在ForResultActivity的返回时,这样返回:

BackResult
        .newBackResult()
        .params(ForResultResIBuilder
                .newBuilder()
                .input(input)
                .input2(input2))
        .finishWithResult(activity);

BackResult是我设计的另外一个助手类,专门为了在activity返回参数的时候用的,非常的简单舒畅,上面的IBuilder类生成后的代码,看一个吧,连他的接口和父类一并列出了(去掉了注释,请直接看SmartKey):

// 接口,已经写好,不需要关注
public interface IntentKeyMapper {
    Intent buildIntent();
}
// 父类,已经写好,有一些比较方便的共用方法可以直接使用,在生成的IBuilder类里使用
public abstract class BaseIntentKeyMapper<B, S> implements IntentKeyMapper {
    protected S smart;
    public S getSmart() {
        return smart;
    }
    public B replaceSmart(@NonNull S smart) {
        if(smart == null)
            throw new RuntimeException("Smart wrapper object should not be null.");

        this.smart = smart;
        return (B) this;
    }
    public abstract B fillFromSource(Intent source);
    public B fillFromSource(Bundle source) {
        if (source == null) return (B) this;
        return fillFromSource(new Intent().putExtras(source));
    }
    public Bundle buildBundle() {
        return buildIntent().getExtras();
    }
}
// 然后就是生成的类了
// req
public final class ForResultReqIBuilder extends BaseIntentKeyMapper<ForResultReqIBuilder, ForResultReq> {
  public ForResultReqIBuilder() {
    smart = new ForResultReq();
  }
  public static ForResultReqIBuilder newBuilder() {
    return new ForResultReqIBuilder();
  }
  public static ForResultReqIBuilder newBuilder(ForResultReq fromSource) {
    return new ForResultReqIBuilder().replaceSmart(fromSource);
  }
  public static ForResultReq getSmart(Intent source) {
    return new ForResultReqIBuilder().fillFromSource(source).getSmart();
  }
  public static ForResultReq getSmart(Bundle source) {
    return new ForResultReqIBuilder().fillFromSource(source).getSmart();
  }
  @Override
  public Intent buildIntent() {
    Intent in = new Intent();
    in.putExtra("title", smart.title);
    in.putExtra("label", smart.label);
    in.putExtra("hint", smart.hint);
    return in;
  }
  public ForResultReqIBuilder fillFromSource(Intent source) {
    if (source == null) { return this; }
    smart.title = source.getStringExtra("title");
    smart.label = source.getStringExtra("label");
    smart.hint = source.getStringExtra("hint");
    return this;
  }
  public ForResultReqIBuilder title(String value) {
    smart.title = value;
    return this;
  }
  public ForResultReqIBuilder label(String value) {
    smart.label = value;
    return this;
  }
  public ForResultReqIBuilder hint(String value) {
    smart.hint = value;
    return this;
  }
}
// res
public final class ForResultResIBuilder extends BaseIntentKeyMapper<ForResultResIBuilder, ForResultRes> {
  public ForResultResIBuilder() {
    smart = new ForResultRes();
  }
  public static ForResultResIBuilder newBuilder() {
    return new ForResultResIBuilder();
  }
  public static ForResultResIBuilder newBuilder(ForResultRes fromSource) {
    return new ForResultResIBuilder().replaceSmart(fromSource);
  }
  public static ForResultRes getSmart(Intent source) {
    return new ForResultResIBuilder().fillFromSource(source).getSmart();
  }
  public static ForResultRes getSmart(Bundle source) {
    return new ForResultResIBuilder().fillFromSource(source).getSmart();
  }
  public Intent buildIntent() {
    Intent in = new Intent();
    in.putExtra("input", smart.input);
    in.putExtra("input2", smart.input2);
    return in;
  }
  public ForResultResIBuilder fillFromSource(Intent source) {
    if (source == null) { return this; }
    smart.input = source.getStringExtra("input");
    smart.input2 = source.getStringExtra("input2");
    return this;
  }
  public ForResultResIBuilder input(String value) {
    smart.input = value;
    return this;
  }
  public ForResultResIBuilder input2(String value) {
    smart.input2 = value;
    return this;
  }
}

注意,以上所有代码都不需要你写,你只要写你的POJO和使用他们,上面的两个POJO我起名字一个叫ForResultReq, 另外一个是ForResultRes,带上Req和Res的目的是为了自己看方便,表明一个是为了传递数据用的,一个是为返回数据用,参照HTTP请求的做法而已,这里POJO类的起名没有任何要求,只要是Java类,直接使用public字段,对于android,一般情况下,还是这样更省CPU时间和内存资源,能省就省吧,对于一般的POJO,并不存在问题。对于遗留key问题,如果目标activity不想改,那么简单,直接把对应字段标注一下,说明key是啥就行了,比如:

// 标注的字段
@Key(Intent.EXTRA_TEXT)
    public String text;
// 对应生成的代码
in.putExtra("android.intent.extra.TEXT", smart.text);
smart.text = source.getStringExtra("android.intent.extra.TEXT");

这样一来目标activity可以不做任何修改,入口可以是全新的了。

  1. 对于framework或者第三方库的兼容问题,跟前面遗留的key管理一样,只需要一个标注@Key(系统或库提供的key),就这样愉快的兼容了。
  2. 还是在第1点上说的,你的Action都会在manifest上面声明,所以@SmartManifest(manifestPath = "app/src/main/AndroidManifest.xml")可以知道这些所有信息,直接生成了对应的goWithAction/goForResultWithAction方法。
  3. NotDeterminedActivityTarge和NotDeterminedServiceTarget两个类专门处理这样的问题,出发点也是SmartTargets,有对应的toNotDeterminedActivityTarge/NotDeterminedServiceTarget方法。
    5和6. 对于SharedPreferences,集中管理,并且使用一个POJO类进行配置,java的字段不允许重复,有重复字段直接编译不通过!!!就这样,key重复的问题一定不会出现,并且每个字段有各自的get/set方法,get就是从SharedPreferences获取,set就是保存到SharedPreferences,至于key,忘掉吧,我会另外写一个博客文章专门介绍SharedPreferences的管理,相关的博客文章即将完成了。

说了这么多,咱么开始具体看看SmartKey提供了什么和怎么用吧。由于本人试了一大圈,注册了一大堆帐号,还是未能发布到mavencentral,所以,用起来有点麻烦,需要大家拷贝代码进项目,有成功发布上mavencentral或者jcenter的朋友可以教我一下,非常感谢。
使用方法如下:

第一步,去SmartKey下载源代码。
第二步,拷贝annotation、apt和sdks三个模块到你的项目里
第三步,在根项目的build.gradle添加以下配置到dependencies配置项内:

        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

第四步,在你的项目下对应的那个主模块的build.gradle下添加以下配置,具体参考下载的代码的app模块:

// 这句放在前面
apply plugin: 'com.neenbedankt.android-apt'
// 这三句放在dependencies配置项内
compile project(':annotation')
compile project(':sdks')
apt project(':apt')

配置就完成了,rebuild一下代码系统就会调用apt工具生成对应的代码。更多内容请参照源码中的app模块,这个模块是一个怎样使用这个库的demo。

下面是具体的使用说明:
annotation模块共有7个注解
@Code注解
这个注解有两个用途,一个用于管理SharedPreferences的时候,有些泛型需要管理的时候标注,另外一个用途是用于标注那些由于继承结构比较复杂,apt工具由于不在android环境下运行,所以并不容易正确生成的代码,例如使用android系统自带的分享功能时,有uri这么一个字段,这个字段用来表示多个文件的路径,类型是ArrayList<Uri>,由于apt工具并不知道uri实现了Parcelable接口,所以生成的代码并不是最好的,可以这样来直接指定生成的代码:

@Key(Intent.EXTRA_STREAM)
@Code(get = "getParcelableArrayListExtra(%1$s)", set = "putParcelableArrayListExtra(%1$s, %2$s)")
public ArrayList<Uri> uri;

上面get表示获取的时候用的代码,%1$s是key的占位符,apt会使用真实的key展开
set表示放进Intent时用的代码,%1$s继续是key的占位符,%2$s是值的占位符,apt会自动匹配真实的值,注意的是,get和set两个值必须同时存在apt才会使用他们,生成代码如下:

smart.uri = source.getParcelableArrayListExtra("android.intent.extra.STREAM");
in.putParcelableArrayListExtra("android.intent.extra.STREAM", smart.uri);

详细例子请参考SmartKey的app模块里面的share包下面的MultiFileShare类,这个类用来描述使用系统自带Intent分享多个图片功能。

@Key注解
这个注解用于指定字段使用的key,一般情况下,新代码根本就不用关注key的问题,这个时候key这个注解就不必要了,当然,如果有遗留代码,又不想改,或者是framework内的比如使用android提供的Intent分享内容,或者使用第三方的库人家的key已经固定了,又或者你就是觉得自己制定的key更好听(起个好字段名不就得了么,默认是直接使用字段名_),就可以用到这个注解了,例如这个用到framework里面现成改不了的key:

// POJO中的用法:
@Key(Intent.EXTRA_EMAIL)
public String[] email;
// 对应生成的代码:
smart.email = (String[]) IntentValueGetter.getValue(source, "android.intent.extra.EMAIL", java.lang.String[].class);
in.putExtra("android.intent.extra.EMAIL", smart.email);

@Required注解
这个注解纯粹给自己看的,在POJO的字段上标识一下,表明这个字段不应该为空,对于这个注解,SmartKey现阶段并不会做任何的处理,目前仅仅为自己看代码服务的。

@SmartIntent注解
用这个注解标注过的POJO类,apt工具会自动扫描所有字段,生成对应的IBuilder类,用于传递数据到目标组件或者从目标组件返回值,属于核心注解,使用SmartKey必用的注解之一,例如前面说到的ForResultReq和ForResultRes类,由于添加了这个注解,所以apt工具为他们生成了ForResultReqIBuilder和ForResultResIBuilder类,直接用这两个builder就可以非常方便的使用方法链传递数据了。

@SmartManifest注解
这个注解一个模块只能出现一次,建议放在对应的主模块,专门用来指定AndroidManifest.xml文件所在的位置,用于生成SmartTargets这个类的,有了这个注解后,apt工具会解析对应的xml文件,把所有activity和service提取出来,生成对应于每一个activity/service的Target描述类,SmartTargets.to方法得到的就是这些生成的Target实例,里面有关于对应activity/service的所有跳转方式方法,是activity跳转/service启动绑定的总入口。

@SmartSharedPreferences注解
这个注解用于集中管理SharedPreferences,具体用法将会用另外一篇文章说明,这里就不详细展开了。

@SmartTarget注解
这个注解用在Activity/Service类上面,目的有两个,一是为了代码阅读的人更轻易的看到目标activity/service用的是哪个POJO作为参数,第二个目的是在前面@SmartManifest注解下生成的对应的Target下,生成一个获取对应POJO的IBuilder实例的方法,例如:

@SmartTarget(req="link.anyauto.smartkey.demo.extras.ForResultReq")
public class ForResultActivity extends BaseActivity {
// 其他activity代码
}
//因为这个注解而生成的代码(在自动生成的你不需要关注的ForResultActivityATarget类里)
public ForResultReqIBuilder newMapperBuilder() {
    return ForResultReqIBuilder.newBuilder();
}
// 传参数的时候可以这样获取这个builder
ForResultReqIBuilder builder = SmartTargets.toForResultActivityATarget().newMapperBuilder();

但其实所有activity/service的Target描述类的params方法都不是指定具体Builder类的,可以传递任何的IntentKeyMapper的实现类。

sdk模块下面的一些类的说明:
BackResult类,用于封装activity结束的时候向调用者返回值的细节工作,用法套路:
BackResult.newBackResult()/.newBackResult(resultCode).params(参数).finishWithResult(activity);
跟前面的activity跳转一样样的:
** BackResult出发,带上resultCode和参数,走起! **
OnPrepareIntentCallback接口,这个接口基本上不怎么需要,这个接口在activity Target的go相关方法调用时会被调用,用于给大家一个最后调整Intent的机会。
GsonHelper类,用于包装json与pojo间的相互转换,如果你需要处理一些非标准格式的日期等字段,需要调用他的replaceGson方法替换成你应用需要的gson对象。
其他都是一些基础性代码,可以完全不关注,当然想知道一些原理,看看还是有用的。

对于未确定的Activity目标,比如根据服务器返回的内容进行跳转,或者根据配置进行跳转时,可以这样使用,一样的套路:

SmartTargets.toNotDeterminedActivityTarget()
                .activityClass(clz) // 或者 .action(action).addCategories(cats).addCategory(cat)
                .params(params)
                .go(activity);

关于Activity的跳转,目前还有一些工作在做,就是引入Activity路由,相关工作正在进行中,为了让大家可以非常简单流畅的使用,我会仔细设计,并且融合现有的参数传递方式,我会完善了再commit到github,让大家的跳转更加舒畅,特别是多人协作,根据服务器内容进行跳转时,使用Activity路由将会更加舒畅。

前面说了这么多,实际用法还是建议大家直接参考app这个模块吧,对于程序员,show me the code比啥都管用。写完文章刚好元宵节,祝愿大家元宵快乐,每天准时下班。喜欢的朋友记得在github上给个星星,多谢了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容

  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,414评论 0 17
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,119评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,656评论 18 139
  • 旋风APP是深圳开拍网运营的影视内容孵化和艺人成长平台 ◆产品简介 旋风App是深圳开拍网科技有限公司(深圳文化所...
    piegroups阅读 449评论 0 0
  • 实现这样的效果,所有文字包括返回按钮都为白色 自定义返回按钮 记得要写在上一个页面上 全局修改UINavigati...
    Arxu阅读 561评论 0 1