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

并行的路.png

这篇文章的实现略有侵入性,但不妨碍你对这方面的思考,更好的实现可以参考另外一篇文章

在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.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容