SmartJump
- 需求
-
- 應用場景
- 實作思路
- 代碼
- 調用示例
- 後記
需求
在跳轉到另一個Activity後,通過回調直接擷取到資料
應用場景
- 普通的activity跳轉,回調擷取資料可以使邏輯更清晰
- 第三方庫中activity資料回調可以讓使用者調用起來更友善
實作思路
- 其實一開始并沒有思路。我自己的一個圖檔選擇架構也實作了圖檔回調,不需要從onActivityResult中擷取。但是我用的方式是在跳轉activity前建立一個RxBus監聽,在擷取到圖檔資料後,用RxBus把資料發送回來,在RxBus裡接收并通過傳入的回調函數将值傳回。用法是沒問題的,但是要多引一個rxjava包,而且實作的思路有點繞。
- 有一天,我在對比幾個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);
}
});
後記
- 使用一個空fragment作為Activity的代理,非常的機智。你可以發現liveData中的ViewModelStores也用到了這個騷操作,有興趣的同學可以看看。
- 有一個遺憾,因為實作方式是借用了一個fragment,而fragment又分為v4下和app下的,本來想相容一下,但是代碼就變得很啰嗦很奇怪。鑒于大部分開發者和谷歌推薦是用v4下fragment,是以就隻支援v4fragment。因而,調用SmartJump的頁面需要繼承fragmentActivity (AppCompatActivity就闊以) 或者v4的fragment。