在项目开发中有时候会碰到这样的需求,就是在没有网络的情况下,点击按钮不进行页面跳转或不执行正常的业务逻辑,其实京东和淘宝等不少app都是这样处理的,面对这样的需求,肯定会想到在用户点击该按钮的时候去做网络的检测,没有网络就提示用户并停止下面的执行,有网络就执行正常的业务逻辑;
public void click(View view){
if(!CheckNetUtil.isNetWorkAvailable(this)){
Toast.makeText(this,"请检测网络",Toast.LENGTH_LONG).show();
return;
}
//正常的业务逻辑
Toast.makeText(this,"网络已连接",Toast.LENGTH_LONG).show();
}
会发现如果需要判断的地方多,及时使用工具类来判断,还是很繁琐,并且后期维护很不方便;这种方法pass掉,接着就是想着在IOC注解出添加上网络的检测,这样也可以;
/**
* 注入事件
*
* @param finder
* @param object
*/
private static void injectEvent(ViewFinder finder, Object object) {
//获取类中所有的方法
Class<?> clazz = object.getClass();
Method[] methods = clazz.getDeclaredMethods();
//获取onclick里面的view值
for(Method method:methods){
Click click = method.getAnnotation(Click.class);
if(click!=null){
int[] viewIds = click.value();
for(int viewId:viewIds){
//findViewById找到view
View view = finder.findViewById(viewId);
//检测网络
boolean isCheckNet=method.getAnnotations()!=null;
if(isCheckNet){
if(!CheckNetUtil.isNetWorkAvailable(MainActivity.this)){
Toast.makeText(MainActivity.this,"请检测网络",Toast.LENGTH_LONG).show();
return;
}
}
if(view!=null){
//view setOnClickListener
view.setOnClickListener(new DeclareOnClickListener(method,object,isCheckNet));
}
}
}
}
}
在事件注入的时候根据是否有checkNet标签来判断是否要检测网络;这样子也可行,下面要说的是AOP编程的方式实现,也就是面向切面编程的方式;
面向切面编程(AOP编程):
把某一方面的一些功能提取出来与一批对象进行隔离,提取之后我们就可以对某个单方面的功能进行编程。
这里是使用aspectj第三方框架来实现的;
下面是使用流程:
第一步:下载
下载地址
第二步:安装
一直点击下一步就可以了,默认安装在c盘,安装完成后,找到安装的路径将aspectjrt.jar文件拷贝到自己项目的lib目录里面,其他的不用拷贝;
拷贝好后,关联到build.gradle文件中;
第三步:在app目录下的build.gradle文件中进行配置;
apply plugin: 'com.android.application'
//配置
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.aspectj:aspectjtools:1.8.9'
classpath 'org.aspectj:aspectjweaver:1.8.9'
}
}
repositories {
mavenCentral()
}
android {
compileSdkVersion 25
buildToolsVersion "26.0.0"
defaultConfig {
applicationId "com.lsm.frameworkday_02"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
//配置
final def log = project.logger
final def variants = project.android.applicationVariants
variants.all { variant ->
if (!variant.buildType.isDebuggable()) {
log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
return;
}
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);
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;
}
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
testCompile 'junit:junit:4.12'
compile files('libs/aspectjrt.jar')
}
配置好后,build下项目并运行下,看有没有问题,没有问题就可以进行编写了;
@Target(ElementType.METHOD)//作用在哪里 ElementType.METHOD作用在方法上
@Retention(RetentionPolicy.RUNTIME)//什么时候编译 RetentionPolicy.RUNTIME运行时编译
public @interface CheckNet {
}
@Aspect
public class SectionAspect {
/**
* 找到处理的切点
* * *(..) 可以处理所有的方法
*/
@Pointcut("execution(@com.lsm.frameworkday_02.CheckNet * *(..))")
public void checkNetBehavior() {
}
@Around("checkNetBehavior()")
public Object checkNet(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
if (signature != null) {
CheckNet checkNet = signature.getMethod().getAnnotation(CheckNet.class);
if (checkNet != null) {
//判断是否有网络
//当前类的上下文 有可能是activity fragment view
Object object = joinPoint.getThis();
Context context = getContext(object);
if (context != null) {
if (!isNetWorkAvailable(context)) {
Toast.makeText(context, "请检测网络", Toast.LENGTH_LONG).show();
return null;
}
}
}
}
return joinPoint.proceed();
}
/**
* 获取上下文
*
* @param object
* @return
*/
private Context getContext(Object object) {
if (object instanceof Activity) {
return (Activity) object;
} else if (object instanceof Fragment) {
Fragment fragment = (Fragment) object;
return fragment.getActivity();
} else if (object instanceof View) {
View view = (View) object;
return view.getContext();
}
return null;
}
/**
* 检测是否有网络
*
* @param context
* @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.getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
}
return false;
}
}
在使用的时候在需要检测网络的方法上面打上@CheckNet标签就可以了;
@CheckNet
public void click(View view){
//正常的业务逻辑
Toast.makeText(this,"网络已连接",Toast.LENGTH_LONG).show();
}
这样子就可以了,并不需要依赖IOC注解,即使多个地方的需求也不会繁琐,可维护性大大提高了。
---------------------
【转载,仅作分享,侵删】
作者:老胡杨
原文:https://blog.csdn.net/wangwo1991/article/details/85954126
|
|