美文网首页android 开发程序员Android开发Android开发
Android拦截器 -- 打开页面自动登录并回来

Android拦截器 -- 打开页面自动登录并回来

作者: 生活简单些 | 来源:发表于2017-04-02 00:27 被阅读1364次

    在App项目中有一些Activity是需要登录成功后才能进去的,比如订单详情页,因为订单是跟账号挂钩的,登录的账号一般会有个ID,需要带着ID和订单号去查订单信息。
    很多刚开始做App的同学会认为应该在进入订单详情页前先确保登录成功,也就是说把登录判断和发起登录都是进入订单详情页前搞定,的确这么做没有问题,但是恐怕体力活会很多吧,如果能理解拦截器的原理就可以简化我们的工作量。

    
    @InterceptWith(LoginInterceptor.class)
    public class OrderDetailActivity extends InterceptorActivity {
        private static final String EXTRA_ORDER_ID = "orderId";
    
        private TextView mOrderInfoText;
        private String mOrderId;
    
        public static void startActivity(Context context, String orderId) {
            Intent intent = new Intent(context, OrderDetailActivity.class);
            intent.putExtra(EXTRA_ORDER_ID, orderId);
            context.startActivity(intent);
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_order_detail);
    
            mOrderId = getIntent().getStringExtra(EXTRA_ORDER_ID);
            mOrderInfoText = (TextView) findViewById(R.id.orderInfo);
        }
    
        @Override
        protected void invoked() {
            super.invoked();
            mOrderInfoText.setText("订单信息(order id: " + mOrderId + ")");
            // 根据orderId请求完整的订单信息
        }
    }
    
    

    看到以上订单详情页只要在Acitvity class之上加上一个登录校验的注解然后并在invoke()回调里执行跟登录相关的接口查询及初始化页面即可,这样就不用关注登录的实现细节,一定程度上解耦了你的业务实现。
    下面我们说说实现方式,当然这里的Interceptor并不是纯粹利用Java的语言的动态代理,这只是一种模仿,依附Activity的生命周期完成的:

    1. 定义Annotation:
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Inherited
    public @interface InterceptWith {
    
        /**
         * @return a Interceptor class array (must have a constructor without parameters inside)
         */
        Class<? extends Interceptor>[] value();
    }
    

    注:如果对Annotation不是很了解最好查阅下相关资料稍微了解下,这里就不过啰嗦了。

    1. 定义Interceptor父类的基本的结构:
    public abstract class Interceptor {
    
        /**
         * Request code used to start activity for result.
         *
         * @return request code
         */
        public abstract int getRequestCode();
    
        /**
         * Check interceptor's condition is meet or no.
         *
         * @param context Android context
         * @return condition is meet or no
         */
        public abstract boolean isSatisfied(Context context);
    
        /**
         * if condition was not satisfied, it'll be called to acquire resource or permission and so on.
         *
         * @param activity see {@link Activity}
         */
        public abstract void process(Activity activity);
    }
    

    注:以上是每个拦截器需要实现的抽象父类,以下以登录校验的拦截器举例:

    public class LoginInterceptor extends Interceptor {
    
        @Override
        public int getRequestCode() {
            return LoginActivity.REQUEST_CODE_LOGIN;
        }
    
        @Override
        public boolean isSatisfied(Context context) {
            return UserConfigCache.isLogin(context);
        }
    
        @Override
        public void process(Activity activity) {
            LoginActivity.startActivityForResult(activity, getRequestCode());
        }
    }
    
    1. 有拦截检测功能的Activity:
    public class InterceptorActivity extends AppCompatActivity {
        private List<Interceptor> mInterceptors = new ArrayList<>();
    
        /**
         * Called only when all interceptors verified OK,
         * so do your work here which all interceptors are passed.
         */
        protected void invoked() {
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            if (mInterceptors.size() == 0) {
                scanInterceptors();
                verifyInterceptors();
            }
        }
    
        private void scanInterceptors() {
            mInterceptors.clear();
    
            InterceptWith annotation = 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() {
            if (mInterceptors.isEmpty()) {
                return;
            }
    
            for (int i = 0; i < mInterceptors.size(); i++) {
                Interceptor interceptor = mInterceptors.get(i);
                if (interceptor.isSatisfied(this)) {
                    if (i == mInterceptors.size() - 1) {
                        invoked();
                        break;
                    }
                } else {
                    interceptor.process(this);
                    break;
                }
            }
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            for (Interceptor interceptor : mInterceptors) {
                if (interceptor.getRequestCode() == requestCode) {
                    if (resultCode == RESULT_OK) {
                        verifyInterceptors();
                        break;
                    } else if (resultCode == RESULT_CANCELED) {
                        finish();
                        break;
                    }
                }
            }
        }
    }
    

    注:
    主要通过在onStart()进行对配置的拦截器进行检查,一旦有拦截器不满足条件就跳转对应的页面(如登录页面)请求资源,当资源请求获取到后(登录成功后)到了ActivityResult再校验其他拦截器,如果配置了多个拦截器则当所有的拦截器都被满足条件后会触发invoked()回调函数执行, 所以需要类似登录成功才能执行的代码就放在invoked()里好了。
    当然配置多个拦截器也很方便:

    @InterceptWith({FirstInterceptor.class, SecondInterceptor.class, ThirdInterceptor.class})
    public class XXXActivity extends InterceptorActivity
    
    1. 以上代码除了LoginInterceptor.java是按业务定义的拦截器,其余都可以作为common模块里的代码或者library中的代码,完整Demo源码请参考Android Interceptor.

    相关文章

      网友评论

      本文标题:Android拦截器 -- 打开页面自动登录并回来

      本文链接:https://www.haomeiwen.com/subject/eenbottx.html