AOP实现Android集中式登录架构

@Override
public boolean isLogin(Context applicationContext) {
return SharePreferenceUtil.getBooleanSp(SharePreferenceUtil.IS_LOGIN, applicationContext);
}
});
}
}

可以看到初始化方法实现了ILogin接口,ILogin接口有两个方法,第一个login()用于接收登录事件,第二个方法isLogin是判断登录状态,这两个方法留给用户自己实现,提高架构的可用性。我们所有的登录请求都会回调到ILogin接口,这也意味着登录事件只有一个统一的入口,这也就是我们集中式登录架构的核心好处了。

好了,我们先来使用以下。

例子1:

//demo演示1 跳转到需要过滤登录的Activity
@LoginFilter(userDefine = 0)
public void onClick(View view) {
startActivity(new Intent(this, SecondActivity.class));
}

上面代码就是监听一个Button的点击事件,然后加入注解@LoginFilter,看方法实现只是跳转到SecondActivity,并没有登录逻辑的判断,但通过这个注解我们就可以在运行时检测是否登录,如果没有登录就会中断方法的执行,转而调用MyApplication里init()方法中我们自己实现的login()方法,login(Context applicationContext, int userDefine)方法中userDefine是留给用户自定义的一个值,为了区别使用哪种登录方式。是不是很简单?再来看例子二:

例子2:

如果我们嫌弃在需要判断登录状态的按钮上加入@LoginFilter()注解麻烦,而是想实现启动一个Activity自动判断是否登录,如果没有登录就回调到我们的ILogin接口,那么你只需要创建一个LoginFilterActivity如下:

//demo演示2 直接过滤登陆,不需要加注解,则继承LoginFilterActivity
public class LoginFilterActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!LoginAssistant.getInstance().getiLogin().isLogin(getApplicationContext())) {
//TODO: 你可以想做什么就做什么,在这里我让页面结束,并给用户提示
Toast.makeText(this, “没有登录!”, Toast.LENGTH_SHORT).show();
finish();
}
}

}

然后我们让需要登录才能进入的Activity继承自LoginFilterActivity就可以了。假如UserActivity继承了LoginFilterActivity,当用户没有登录的时候,我们启动UserActivity的时候便会回调到我们的ILogin接口,是不是很方便,这就是我们今天要讲的集中式登录架构。

下面,我们来讲一讲如何实现这个架构。

AOP原理

我们先来了解一下AOP,因为这个架构是基于AOP编程实现的。

  • 什么是AOP

关于AOP是什么,这里我简单介绍一下,AOP是Aspect Oriented Programming的缩写,即面向切面编程,与面向对象编程(oop)是两种不同的思维方式,也可以看做是对oop的一种补充。传统的oop开发会提倡功能模块化等,而aop适合于针对某一类型的问题统一处理。AOP思想的讲解不是我们本篇文章的重点,如果有同学对AOP思想不是很理解,这里我推荐一篇文章,讲得很不错Java AOP & Spring AOP 原理和实现

  • AspectJ介绍

AspectJ是一个面向切面编程的一个框架,它扩展了java语言,并定义了实现AOP的语法。我们知道,在将.java文件编译为.class文件时默认使用javac编译工具,而AspectJ会有一套符合java字节码编码规范的编译工具来替代javac,在将.java文件编译为.class文件时,会动态的插入一些代码来做到对某一类特定东西的统一处理。我举个例子,比如在应用中有很多个button的onClick事件需要检测是否登录,如果没有登录则需要去登录之后才能继续执行,针对这一类型的问题,相对笨一点的做法就是在每一个onClick方法中都显式的去判断登录状态,这样不免过于麻烦。而我们用AOP的方式实现的话,就需要在每一个onClick方法上加入一个标注,让编译器在编译时能识别到这个标注,然后根据标注来生成一些代码检测登录状态。好了,如果有同学对AOP还不是很理解的话也不用急,下面我会用例子来给大家演示如何使用AOP实现统一的集中式登录。

AOP实现集中式登录
  • aspectj环境搭建

首先,我们导入AspectJ的jar包,AspectJ的jar网上一搜就有,也可以直接去我demo里面拿,LoginArchitecture AOP实现集中式登录 github链接点我。demo里jar包导入: 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
好了,导入jar后还需要在app.gradle配置如下:

buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath ‘org.aspectj:aspectjtools:1.8.8’
classpath ‘org.aspectj:aspectjweaver:1.8.8’
}
}

然后在文件末尾添加如下代码:

import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
//标注1
final def log = project.logger
final def variants = project.android.applicationVariants

variants.all { variant ->
//标注2
if (!variant.buildType.isDebuggable()) {
log.debug(“Skipping non-debuggable build type ‘${variant.buildType.name}’.”)
return;
}
//标注3
JavaCompile javaCompile = variant.javaCompile
javaCompile.doLast {
String[] args = [“-showWeaveInfo”,
“-1.8”,
“-inpath”, javaCompile.destinationDir.toString(),
“-aspectpath”, javaCompile.classpath.asPath,
“-d”, javaCompile.destinationDir.toString(),
“-classpath”, javaCompile.classpath.asPath,
“-bootclasspath”, project.android.bootClasspath.join(File.pathSeparator)]
log.debug "ajc args: " + Arrays.toString(args)

MessageHandler handler = new MessageHandler(true);
new Main().run(args, handler);
//标注4
for (IMessage message : handler.getMessages(null, true)) {
switch (message.getKind()) {
case IMessage.ABORT:
case IMessage.ERROR:
case IMessage.FAIL:
log.error message.message, message.thrown
break;
case IMessage.WARNING:
log.warn message.message, message.thrown
break;
case IMessage.INFO:
log.info message.message, message.thrown
break;
case IMessage.DEBUG:
log.debug message.message, message.thrown
break;
}
}
}
}

关于上面这一大片代码就是对aspectj的配置,先看标注1,获取log打印工具和构建配置,然后标注2判断是否debug,如果打release把return去掉就可以,标注3处意思是使aspectj配置生效,标注4就是为了在编译时打印信息如警告、error等等,这些东西在网上也有很多,大家如果不理解,可以去搜索一下,这里不再详细解释。

  • 切面代码编写

好了,配置完上面的内容之后,我们就开始编写代码了,首先,定义一个注解LoginFilter,用来注解方法,以便在编译期被编译器检测到需要做切面的方法。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LoginFilter {

int userDefine() default 0;

}

大家看到我在注解里加了个userDefine,就是为了给用户提供自定义实现,如根据userDifine值不同做不同的登录处理。

然后,编写LoginSDK文件用于初始化和接收登录事件,代码如下:

public class LoginSDK {

public void init(Context context, ILogin iLogin) {
applicationContext = context.getApplicationContext();
LoginAssistant.getInstance().setApplicationContext(context);
LoginAssistant.getInstance().setiLogin(iLogin);
}

//…

}

然后,新建LoginFilterAspect.java文件用来处理加入LoginFilter注解的方法,对这些方法做统一的切面处理。

@Aspect

更多Android高级工程师进阶学习资料

进阶学习视频

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

那么很难做到真正的技术提升。**

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值