AOP 面向切面编程
1.使用场景还原
当我们打开京东 app 进入首页,如果当前是没有网络的状态,里面的按钮点击是没有反应的。只有当我们打开网络的情况下,点击按钮才能跳转页面.按照我们一般人写代码的逻辑应该是这个样子:
/**
* 跳转到待收货页面
*/
public void jumpWaitReceiving() {
if(CheckNetUtil.isNetworkAvailable(this)) {
Intent intent = new Intent(this, WaitReceivingActivity.class);
startActivity(intent);
}
}
/**
* 跳转到我的钱包页面
*/
public void jumpMineWallet() {
if(CheckNetUtil.isNetworkAvailable(this)) {
Intent intent = new Intent(this, MineWalletActivity.class);
startActivity(intent);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
分析:当然,上面只有2个按钮,也就只检测了2次,写了2次网络监测,但是如果项目中的其他很多地方(几十处几百处)需要用到网络监测的话,就非常麻烦了,需要重复写很多次上面的if条件.而且这仅仅是网络监测,万一要需要在这里加入网络埋点、友盟统计、日志打印、日志上传、登录判断,权限判断等等。那就更加麻烦了,需要重复写的地方更多。
2.在Android Studio中引入AspectJ
在项目的根目录的build.gradle文件中添加依赖,修改后文件如下
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:1.0.8'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
然后在项目或者库的build.gradle文件中添加AspectJ的依赖
compile 'org.aspectj:aspectjrt:1.8.9'
同时在该文件中加入AspectJX模块
apply plugin: 'android-aspectjx'
3.AOP 偷懒式网络访问
/**
* 跳转到待收货页面
*/
@CheckNet
public void jumpWaitReceiving() {
Intent intent = new Intent(this, WaitReceivingActivity.class);
startActivity(intent);
}
/**
* 跳转到我的钱包页面
*/
@CheckNet
public void jumpMineWallet() {
Intent intent = new Intent(this, MineWalletActivity.class);
startActivity(intent);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
上面我只是加了1个注解,就实现了执行方法前的网络监测(其实还需要写下面的SectionNetAspect)。
这个注解是我自己写的,如下:
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckNet {
}
这里,解释一下,上面的Retention,首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。
有了这个注解之后,就可以写到需要监测网络的地方,然后再写处理网络监测切面。其实就是在工程里面建一个类,随便放在哪里都行,随便什么名字都可以。
/**
* author feiyang
* create at 2017/9/4 16:23
* description:处理网络监测切面
*/
@Aspect
public class SectionNetAspect {
private static final String TAG = "SectionNetAspect";
/**
* 找到处理的切点
* * *(..) 可以处理所有的方法
*/
@Pointcut("execution(@com.xfhy.aspectjdemo.CheckNet * *(..))")
public void checkNetBehavior() {
}
/**
* 处理切面
*/
@Around("checkNetBehavior()")
public Object checkNet(ProceedingJoinPoint joinPoint) throws Throwable {
Log.e(TAG, "checkNet");
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
CheckNet checkNet = signature.getMethod().getAnnotation(CheckNet.class);
if (checkNet != null) {
Log.e(TAG, "判断有没有网络");
Object object = joinPoint.getThis();
Context context = getContext(object);
if (!isNetworkAvailable(context)) {
Toast.makeText(context, "请检查您的网络", Toast.LENGTH_SHORT).show();
return null;
}
}
return joinPoint.proceed();
}
private Context getContext(Object object) {
if (object instanceof Activity) {
return (Activity) object;
} else if (object instanceof Fragment) {
return ((Fragment) object).getActivity();
} else if (object instanceof View) {
return ((View) object).getContext();
}
return null;
}
/**
* 检查当前网络是否可用
*
* @return
*/
private static boolean isNetworkAvailable(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
NetworkInfo[] networkInfo = connectivityManager.getAllNetworkInfo();
if (networkInfo != null && networkInfo.length > 0) {
for (int i = 0; i < networkInfo.length; i++) {
if (networkInfo[i].getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
}
return false;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
现在好了,把上面这个类放到项目中,即可在需要的地方加入 @CheckNet,即可监测是否有网络。简单吧,very nice。