天天看點

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。