天天看点

SmartAndroid之SmartJump,告别onActivityResult需求

SmartJump

  • 需求
    • 应用场景
    • 实现思路
    • 代码
    • 调用示例
    • 后记

需求

在跳转到另一个Activity后,通过回调直接获取到数据

应用场景

  1. 普通的activity跳转,回调获取数据可以使逻辑更清晰
  2. 第三方库中activity数据回调可以让使用者调用起来更方便

实现思路

  1. 其实一开始并没有思路。我自己的一个图片选择框架也实现了图片回调,不需要从onActivityResult中获取。但是我用的方式是在跳转activity前建立一个RxBus监听,在获取到图片数据后,用RxBus把数据发送回来,在RxBus里接收并通过传入的回调函数将值返回。用法是没问题的,但是要多引一个rxjava包,而且实现的思路有点绕。
  2. 有一天,我在对比几个permission请求库的优劣的时候发现,RxPermission有个很棒的优点,不需要重写onPermissionsGranted,很是神奇。因为RxPermission代码比较少,很快我就搞明白了大佬是怎么实现的。大佬在请求权限的时候先启动了一个fragment,然后在fragment里请求权限,又在fragment的onRequestPermissionsResult中把请求结果回调。这就是传说中的代理模式嘛?大佬真的厉害,Or2。既然请求权限可以这么搞,那么跳转回调也就是一样的道理了。于是,我照着大神的代码,怼了怼,搞出了新的跳转库,很简单就一个类

代码

public class SmartJump {


    private static final String TAG = BuildConfig.APPLICATION_ID + SmartJump.class.getSimpleName();

    private ResultBridgeFragment resultBridgeFragment;

    public static SmartJump from(@NonNull FragmentActivity activity) {
        return new SmartJump(activity.getSupportFragmentManager());
    }

    public static SmartJump from(@NonNull Fragment fragment) {
        return new SmartJump(fragment.getChildFragmentManager());
    }

    public static SmartJump with(@NonNull FragmentManager fragmentManager) {
        return new SmartJump(fragmentManager);
    }

    @SuppressWarnings("WeakerAccess")
    public void startForResult(Intent intent, Callback callback) {
        resultBridgeFragment.startForResult(intent, callback);
    }

    public void startForResult(Class<?> clazz, Callback callback) {
        Intent intent = new Intent(resultBridgeFragment.getActivity(), clazz);
        startForResult(intent, callback);
    }

    public interface Callback {
        /**
         * 回调
         *
         * @param resultCode code
         * @param data       data
         */
        void onActivityResult(int resultCode, Intent data);
    }


    private SmartJump(FragmentManager fragmentManager) {
        resultBridgeFragment = getResultBridgeFragment(fragmentManager);
    }

    private ResultBridgeFragment getResultBridgeFragment(@NonNull final FragmentManager fragmentManager) {
        ResultBridgeFragment bridgeFragment = (ResultBridgeFragment)fragmentManager.findFragmentByTag(TAG);
        // 假如fragment 已经添加过了  就不用重复添加了
        if (bridgeFragment == null) {
            bridgeFragment = new ResultBridgeFragment();
            fragmentManager
                    .beginTransaction()
                    .add(bridgeFragment, TAG)
                    .commitNow();
        }
        return bridgeFragment;
    }

   public  static class ResultBridgeFragment extends Fragment {
        private SparseArray<Callback> mCallbacks = new SparseArray<>();
        /**
         * 每次启动都会有个不同的requestCode
         * 因为某个activity可能会多个跳转回调
         */
        private int uniqueCode = 1;

        public ResultBridgeFragment() {
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // 设备旋转 数据保留
            setRetainInstance(true);
        }


        /**
         * 防止 同时多个activity启动 造成request相同
         *
         * @param intent   intent
         * @param callback 回调
         */
        public synchronized void startForResult(Intent intent, Callback callback) {
            // 保证requestCode 每个都不同
            uniqueCode++;
            mCallbacks.put(uniqueCode, callback);
            startActivityForResult(intent, uniqueCode);
        }

        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            Callback callback = mCallbacks.get(requestCode);
            if (callback != null) {
                callback.onActivityResult(resultCode, data);
            }
            mCallbacks.remove(requestCode);
        }
    }
}
           

调用示例

SmartJump.from(this).startForResult(TestBackActivity.class, new SmartJump.Callback() {
                    @Override
                    public void onActivityResult(int resultCode, Intent data) {
                        ToastUtils.showMessage("jump_a backButton" + resultCode);
                    }
                });
           

后记

  1. 使用一个空fragment作为Activity的代理,非常的机智。你可以发现liveData中的ViewModelStores也用到了这个骚操作,有兴趣的同学可以看看。
  2. 有一个遗憾,因为实现方式是借用了一个fragment,而fragment又分为v4下和app下的,本来想兼容一下,但是代码就变得很啰嗦很奇怪。鉴于大部分开发者和谷歌推荐是用v4下fragment,所以就只支持v4fragment。因而,调用SmartJump的页面需要继承fragmentActivity (AppCompatActivity就阔以) 或者v4的fragment。