??之前寫過一篇文章茧痕,講解如何解耦頁面跳轉(zhuǎn)和自動登錄,至于思想想必看過那篇文章的人都懂了,簡單說就是很多地方都會跳轉(zhuǎn)某個頁面(稱呼為A頁面)龟虎,但A頁面需要登錄后才能加載數(shù)據(jù),我們不希望發(fā)起跳轉(zhuǎn)的頁面負責(zé)登錄判斷和登錄的工作茎用,即:登錄判斷和跳轉(zhuǎn)登錄應(yīng)該是A頁面自己的份內(nèi)工作遣总。
??只是,之前的實現(xiàn)有代碼侵入性轨功,需要改動現(xiàn)有的BaseActivity, 讓Activity賦予能做注解解析功能旭斥,很明顯這是有侵入性的。
??新的實現(xiàn)方案是創(chuàng)建一個無UI的Fragment的代理古涧,它負責(zé)做真正的startActivityForResult()
垂券,隨后的activityResult通過它們之間的callback傳給創(chuàng)建無UI Fragment的Activity或者Fragment,這原理其實很簡單羡滑。因此菇爪,我們又有了另外一個發(fā)現(xiàn):簡化startActivityForResult()
, 即:以掛回調(diào)的方式處理activityResult。
??其實柒昏,Android 6.0權(quán)限請求的API跟startActivityForResult()
及其類似(requestPermissions (String[] permissions, int requestCode)
和 onRequestPermissionsResult (int requestCode, String permissions[], int[] grantResults)
)凳宙,在此之前也寫過篇文章如何通過此原理簡化了Android 6.0權(quán)限的請求。
如下演示了幾個案例:
- 如何在Activity中打開需要先登錄的訂單詳情頁职祷;
- 如何在Fragment中打開需要先登錄的訂單詳情頁氏涩;
- 打開不僅要登錄還要授權(quán)的管理員頁面;
- 在Activity中以掛回調(diào)的方式startActivityForResult()接收activityResult有梆;
- 在Fragment中以掛回調(diào)的方式startActivityForResult()接收activityResult是尖;
1. Activity攔截器新的接入方式:
// 1. open OrderDetailActivity
Intent intent = new Intent(context, OrderDetailActivity.class);
startActivity(intent);
// 2. implementation of OrderDetailActivity
@InterceptWith(LoginInterceptor.class)
public class OrderDetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_order_detail);
ActivityResult result = new ActivityResult(this);
result.intercept(new OnInterceptResult() {
/**
* init data or load data from http and so on after all interceptors is validated.
*/
@Override
public void invoke() {
TextView imageView = findViewById(R.id.contentView);
imageView.setText("This Is the Order Detail Page");
}
});
}
}
ActivityResult
對象的創(chuàng)建可以在Activity也可在Fragment。
如果需要多個校驗攔截泥耀,配置方式跟以前一樣(當(dāng)所有Interceptor都校驗通過才會觸發(fā)invoke()
執(zhí)行):
@InterceptWith({LoginInterceptor.class, PermissionInterceptor.class})
public class AdminActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin_activity);
ActivityResult activityResult = new ActivityResult(this);
activityResult.intercept(new OnInterceptResult() {
@Override
public void invoke() {
TextView textView = findViewById(R.id.contentView);
textView.setText("This The Admin Manager page");
}
});
}
}
那么LoginInterceptor.java是一個根據(jù)業(yè)務(wù)定義的校驗器饺汹,讓我們看看如何實現(xiàn):
public class LoginInterceptor extends Interceptor {
@Override
public boolean isValid(Context context) {
return LoginActivity.isLogin(context);
}
@Override
public Intent getTargetIntent(Context context) {
return new Intent(context, LoginActivity.class);
}
}
其實,只要給出校驗規(guī)則以及校驗不通過要跳轉(zhuǎn)的頁面Intent即可痰催。
2. 以掛回調(diào)的方式接收activityResult:
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
ActivityResult activityResult = new ActivityResult(this);
activityResult.startActivityForResult(intent, new OnResultCallback() {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
String phoneNum = Util.resolvePhoneNumber(getApplicationContext(), data.getData());
Toast.makeText(MainActivity.this, "phone number: " + phoneNum, Toast.LENGTH_SHORT).show();
}
});
3. 如何實現(xiàn)之ActivityResult:
public class ActivityResult {
private static final String TAG = ActivityResult.class.getSimpleName();
private FragmentManager mFragmentManager;
private List<Interceptor> mInterceptors = new ArrayList<>();
private Lazy<ResultFragment> mResultFragment;
private FragmentActivity mFragmentActivity;
public ActivityResult(FragmentActivity activity) {
mFragmentActivity = activity;
mFragmentManager = activity.getSupportFragmentManager();
mResultFragment = getLazySingleton();
findInterceptors(activity);
}
public ActivityResult(Fragment fragment) {
mFragmentActivity = fragment.getActivity();
mFragmentManager = fragment.getChildFragmentManager();
mResultFragment = getLazySingleton();
findInterceptors(fragment);
}
/**
* Convenient method to start activity for result.
*/
public void startActivityForResult(Intent intent, OnResultCallback callback) {
mResultFragment.get().startActivityForResult(intent, callback);
}
/**
* Check if interceptors specified with annotation {@link InterceptWith} are valid or not.
*/
public void intercept(final OnInterceptResult onInterceptResult) {
boolean isNewInstance = mFragmentManager.findFragmentByTag(TAG) == null;
OnResultCallback onResultCallback = new OnResultCallback() {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
for (Interceptor interceptor : mInterceptors) {
if (requestCode == interceptor.getRequestCode()){
if (resultCode == Activity.RESULT_OK) {
verifyInterceptors(true, onInterceptResult, this);
break;
} else if (resultCode == Activity.RESULT_CANCELED) {
mFragmentActivity.finish();
break;
}
}
}
}
};
mResultFragment.get().setResultCallback(onResultCallback);
// verify interceptors
if (!mInterceptors.isEmpty()) {
verifyInterceptors(isNewInstance, onInterceptResult, onResultCallback);
}
}
private void findInterceptors(Object object) {
mInterceptors.clear();
InterceptWith annotation = object.getClass().getAnnotation(InterceptWith.class);
if (annotation != null) {
Class<? extends Interceptor>[] classes = annotation.value();
for (Class<? extends Interceptor> clazz : classes) {
try {
mInterceptors.add(clazz.newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
/**
* new instance need to invoke process
*/
private void verifyInterceptors(boolean isNewInstance, OnInterceptResult onInterceptResult, OnResultCallback onResultCallback) {
if (mInterceptors.isEmpty()) {
return;
}
for (int i = 0; i < mInterceptors.size(); i++) {
Interceptor interceptor = mInterceptors.get(i);
if (interceptor.isValid(mResultFragment.get().getContext())) {
// invoke callback if all validations pass
if (i == mInterceptors.size() - 1) {
onInterceptResult.invoke();
break;
}
} else if (isNewInstance){
Intent intent = interceptor.getTargetIntent(mFragmentActivity);
int requestCode = mResultFragment.get().startActivityForResult(intent, onResultCallback);
interceptor.setRequestCode(requestCode);
break;
}
}
}
@NonNull
private Lazy<ResultFragment> getLazySingleton() {
return new Lazy<ResultFragment>() {
private ResultFragment permissionsFragment;
@Override
public synchronized ResultFragment get() {
if (permissionsFragment == null) {
permissionsFragment = getResultFragment();
permissionsFragment.setLogging(true);
}
return permissionsFragment;
}
};
}
private ResultFragment getResultFragment() {
ResultFragment permissionsFragment = (ResultFragment) mFragmentManager.findFragmentByTag(TAG);
boolean isNewInstance = permissionsFragment == null;
if (isNewInstance) {
permissionsFragment = new ResultFragment();
mFragmentManager
.beginTransaction()
.add(permissionsFragment,TAG)
.commitNowAllowingStateLoss();
}
return permissionsFragment;
}
@FunctionalInterface
interface Lazy<V> {
V get();
}
}
兩個構(gòu)造函數(shù)使得可以在Activity和Fragment里工作兜辞,了解之前文章的朋友會發(fā)現(xiàn)解析注解的工作現(xiàn)在放在了
ActivityResult
里了,不再需要篡改Activity了陨囊。ActivityResult
的作用就是創(chuàng)建ResultFragment
并委托其startActivityForResult()
, 隨后的結(jié)果返回通過OnResultCallback
或者OnInterceptResult
傳遞出去弦疮。
4. 如何實現(xiàn)之ResultFragment:
public class ResultFragment extends Fragment {
private static final String TAG = "ResultFragment";
private SparseArray<OnResultCallback> mResultCallbackStorage = new SparseArray<>();
private int mRequestCode = 200;
private boolean mLogging;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
int startActivityForResult(Intent intent, OnResultCallback callback) {
mResultCallbackStorage.put(++mRequestCode, callback);
startActivityForResult(intent, mRequestCode);
return mRequestCode;
}
void setResultCallback(OnResultCallback callback) {
mResultCallbackStorage.put(++mRequestCode, callback);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
OnResultCallback callback = mResultCallbackStorage.get(requestCode);
if (callback != null) {
callback.onActivityResult(requestCode, resultCode, data);
}
}
void setLogging(boolean logging) {
mLogging = logging;
}
void log(String message) {
if (mLogging) {
Log.d(TAG, message);
}
}
}
ResultFragment的實現(xiàn)非常簡單,它就是一個普通Fragment蜘醋,負責(zé)把activityResult通過callback回傳給它的創(chuàng)建者胁塞。
完整實現(xiàn)可以參考這里