打开页面自动登录并回来-拦截器(升级版)
之前写过一篇文章,讲解如何解耦页面跳转和自动登录,至于思想想必看过那篇文章的人都懂了,简单说就是很多地方都会跳转某个页面(称呼为A页面),但A页面需要登录后才能加载数据,我们不希望发起跳转的页面负责登录判断和登录的工作,即:登录判断和跳转登录应该是A页面自己的份内工作。
只是,之前的实现有代码侵入性,需要一个让A页面继承一个叫InterceptorActivity
的页面(负责注解解析和校验),又恐怕大家项目都已经有了一个所谓的BaseActivity,逼不得已要改动此BaseActivity让其继承InterceptorActivity
, 很明显这是有侵入性的。
新的实现方案是创建一个无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和Fragment中以挂回调的方式startActivityForResult()接收activityResult:
activity_result.gif1. 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(this) {
/**
* 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(this) {
@Override
public void invoke() {
TextView textView = findViewById(R.id.contentView);
textView.setText("This The Admin Manager page");
}
});
}
}
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) {
if (resultCode == Activity.RESULT_OK) {
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 List<Interceptor> mInterceptors = new ArrayList<>();
private Lazy<ResultFragment> mResultFragment;
public ActivityResult(FragmentActivity activity) {
mResultFragment = getLazySingleton(activity.getSupportFragmentManager());
findInterceptors(activity);
}
public ActivityResult(Fragment fragment) {
mResultFragment = getLazySingleton(fragment.getChildFragmentManager());
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 callback) {
mResultFragment.get().intercept(new OnResultCallback() {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
for (Interceptor interceptor : mInterceptors) {
if (interceptor.getRequestCode() == requestCode) {
if (resultCode == Activity.RESULT_OK) {
verifyInterceptors(callback);
break;
} else if (resultCode == Activity.RESULT_CANCELED) {
callback.finishSelf();
break;
}
}
}
}
});
// verify interceptors
if (!mInterceptors.isEmpty()) {
verifyInterceptors(callback);
}
}
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();
}
}
}
}
private void verifyInterceptors(OnInterceptResult callback) {
if (mInterceptors.isEmpty()) {
return;
}
for (int i = 0; i < mInterceptors.size(); i++) {
Interceptor interceptor = mInterceptors.get(i);
if (interceptor.isValid(mResultFragment.get().getContext())) {
if (i == mInterceptors.size() - 1) {
callback.invoke();
break;
}
} else {
interceptor.process(mResultFragment.get());
break;
}
}
}
@NonNull
private Lazy<ResultFragment> getLazySingleton(@NonNull final FragmentManager fragmentManager) {
return new Lazy<ResultFragment>() {
private ResultFragment permissionsFragment;
@Override
public synchronized ResultFragment get() {
if (permissionsFragment == null) {
permissionsFragment = getPermissionsFragment(fragmentManager);
permissionsFragment.setLogging(true);
}
return permissionsFragment;
}
};
}
private ResultFragment getPermissionsFragment(@NonNull final FragmentManager fragmentManager) {
ResultFragment permissionsFragment = (ResultFragment) fragmentManager.findFragmentByTag(TAG);
boolean isNewInstance = permissionsFragment == null;
if (isNewInstance) {
permissionsFragment = new ResultFragment();
fragmentManager
.beginTransaction()
.add(permissionsFragment, TAG)
.commitNow();
}
return permissionsFragment;
}
@FunctionalInterface
interface Lazy<V> {
V get();
}
}
两个构造函数使得可以在Activity和Fragment里工作,了解之前文章的朋友会发现解析注解的工作现在放在了
ActivityResult
里了,不再依赖Override Activity了。ActivityResult
的作用就是创建ResultFragment
并委托其startActivityForResult()
, 随后的结果返回通过OnResultCallback
或者OnInterceptResult
传递出去。
4. 如何实现之ResultFragment:
/**
* It's a interceptor fragment and it is used to startActivityForResult()
* and pass activity result to its observer via callback.
*/
public class ResultFragment extends Fragment {
private static final String TAG = "PermissionsFragment";
public static final int REQUEST_CODE = 9998;
private OnResultCallback mOnResultCallback;
private boolean mLogging;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
void startActivityForResult(Intent intent, OnResultCallback callback) {
startActivityForResult(intent, REQUEST_CODE);
mOnResultCallback = callback;
}
void intercept(OnResultCallback callback) {
mOnResultCallback = callback;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mOnResultCallback.onActivityResult(requestCode, resultCode, data);
}
}
ResultFragment的实现非常简单,它就是一个普通Fragment,负责把activityResult通过callback回传给它的创建者。
完整实现可以参考这里