之前写过一篇文章,讲解如何解耦页面跳转和自动登录,至于思想想必看过那篇文章的人都懂了,简单说就是很多地方都会跳转某个页面(称呼为A页面),但A页面需要登录后才能加载数据,我们不希望发起跳转的页面负责登录判断和登录的工作,即:登录判断和跳转登录应该是A页面自己的份内工作。

只是,之前的实现有代码侵入性,需要改动现有的BaseActivity, 让Activity赋予能做注解解析功能,很明显这是有侵入性的。
新的实现方案是创建一个无UI的Fragment的代理,它负责做真正的startActivityForResult(),随后的activityResult通过它们之间的callback传给创建无UI Fragment的Activity或者Fragment,这原理其实很简单。因此,我们又有了另外一个发现:简化startActivityForResult(), 即:以挂回调的方式处理activityResult。
其实,Android 6.0权限请求的API跟startActivityForResult()及其类似(requestPermissions (String[] permissions, int requestCode) 和 onRequestPermissionsResult (int requestCode, String permissions[], int[] grantResults)),在此之前也写过篇文章如何通过此原理简化了Android 6.0权限的请求。
如下演示了几个案例:
- 如何在Activity中打开需要先登录的订单详情页;
- 如何在Fragment中打开需要先登录的订单详情页;
- 打开不仅要登录还要授权的管理员页面;
- 在Activity中以挂回调的方式startActivityForResult()接收activityResult;
- 在Fragment中以挂回调的方式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对象的创建可以在Activity也可在Fragment。
如果需要多个校验拦截,配置方式跟以前一样(当所有Interceptor都校验通过才会触发invoke()执行):
@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是一个根据业务定义的校验器,让我们看看如何实现:
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);
}
}
其实,只要给出校验规则以及校验不通过要跳转的页面Intent即可。
2. 以挂回调的方式接收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. 如何实现之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();
}
}
两个构造函数使得可以在Activity和Fragment里工作,了解之前文章的朋友会发现解析注解的工作现在放在了
ActivityResult里了,不再需要篡改Activity了。ActivityResult的作用就是创建ResultFragment并委托其startActivityForResult(), 随后的结果返回通过OnResultCallback或者OnInterceptResult传递出去。
4. 如何实现之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的实现非常简单,它就是一个普通Fragment,负责把activityResult通过callback回传给它的创建者。
完整实现可以参考这里