打开页面自动登录并回来-拦截器(升级版)

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

inteceptor.png

  只是,之前的实现有代码侵入性,需要改动现有的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权限的请求。

如下演示了几个案例:

  1. 如何在Activity中打开需要先登录的订单详情页;
  2. 如何在Fragment中打开需要先登录的订单详情页;
  3. 打开不仅要登录还要授权的管理员页面;
  4. 在Activity中以挂回调的方式startActivityForResult()接收activityResult;
  5. 在Fragment中以挂回调的方式startActivityForResult()接收activityResult;
activity_result.gif

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 mInterceptors = new ArrayList<>();
    private Lazy 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[] classes = annotation.value();
            for (Class 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 getLazySingleton() {
        return new Lazy() {
            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 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 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回传给它的创建者。

完整实现可以参考这里

你可能感兴趣的:(打开页面自动登录并回来-拦截器(升级版))