SmartAndroid之SmartJump,告别onActivityResult

【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 datadata */ 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; }publicstatic class ResultBridgeFragment extends Fragment { private SparseArray 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 intentintent * @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。

    推荐阅读