开启生长之旅!这是我参与「日新计划 12 月更文挑战」的第35天,点击检查活动概况

问题

最近遇到了一个很有趣的问题,为什么不能够用回调的办法运用startActivityForResult呢?假如咱们想要用回调的办法运用,有什么问题? 首先咱们看一下目前官方的运用办法,如下图所示

回调的方式使用startActivityForResult
其实这个流程很复杂,很不符合高内聚的准则,特别是假如页面的恳求许多就会变成如下的情况

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode){
            case 1:
                break;
            case 2:
                break;
            case 3:
                break;
            .....          
        }
    }

假如咱们想要实现成回调的办法呢?

回调实现

参阅这篇博客,juejin.im/entry/5b9a6… 有几种实现办法:

  1. 运用一个代理类,帮助处理startActivityForResult和onActivityResult,本质上和原生运用办法没有差异,仍是有必要要在Activity里的onActivityResult 里边手动的调用;
  2. 运用反射或者AOP,修正onActivityResult的流程,但稳定性和兼容性较差,而且可能会和其他的结构产生抵触;
  3. 比较引荐的便是这个办法,在Activity里边添加一个空的fragment,经过这个fragment发起恳求和接纳成果,然后将收到的成果用回调函数传递给Activity。

回调的问题

那么为什么官方不设计成回调的办法呢?像下面这样子,回调的办法有啥问题

 startActivityForResult(intent, new CallBack() {
      @Override
      public void onActivityResult(int resultCode, Intent data) {
      }
  });

匿名内部类的结构函数 在上述的例子当中,callback是一个匿名内部类,咱们都知道匿名内部类会持有外部类的引用,那这个引用是何时传入的呢? 咱们经过反射来检查以下匿名内部类的结构函数

private void reflect(Object callback){
    Class cl = callback.getClass();
     //结构函数
     Constructor[] declaredConstructors = cl.getDeclaredConstructors();
     for (Constructor constructor:declaredConstructors){
         Log.i("结构函数",constructor.toString());
     }
}

经过打印能够看到结构函数如下

回调的方式使用startActivityForResult
也便是编译器在编译的时分替咱们生成了一个结构函数,而且将对应的activity当作参数传入。

Activity被毁掉的场景 若咱们考虑下面这种情况,当A运用回调的办法跳转到B,此刻因为某种原因A被毁掉了,然后当B履行完结返回成果,体系会从头创立A1,而callback里边持有的是A引用,并不会对A1产生效果,这显然不是咱们想要的成果。

回调的方式使用startActivityForResult
当activity被重建,咱们能够经过反射,将新的activity从头set进去,这样callback引用的便是重建后的新的activity了。

Class cl = callback.getClass();
 Field[] fields = cl.getDeclaredFields();
 for(Field f : fields) {
     try {
         f.setAccessible(true); // 设置些特点是能够访问的
         String type = f.getType().toString(); // 得到此特点的类型
         String name = f.getName();// 得到特点的称号
         if(type.equals(FirstActivity.class.toString())) {
             f.set(callback, this.getActivity());
         }
         Log.i("字段信息", type + ", " + name);
     } catch (Exception e) {
         e.printStackTrace();
     }
 }

定论

在Activity当中添加一个空的fragment能够处理此问题,但关于Activity毁掉和重建的场景则需额定处理,因为反射会损耗功能, 初步想法是添加Activity生命周期的感知才能,当感知到Activity有毁掉重建的动作,则运用反射从头设置一下。