A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 不二晨 金牌黑马   /  2019-1-18 10:24  /  736 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

在项目开发中有时候会碰到这样的需求,就是在没有网络的情况下,点击按钮不进行页面跳转或不执行正常的业务逻辑,其实京东和淘宝等不少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第三方框架来实现的;

下面是使用流程:

第一步:下载

下载地址

第二步:安装

20190106223439282.png

一直点击下一步就可以了,默认安装在c盘,安装完成后,找到安装的路径将aspectjrt.jar文件拷贝到自己项目的lib目录里面,其他的不用拷贝;
20190106223759441.png


拷贝好后,关联到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


3 个回复

倒序浏览
看一看。
回复 使用道具 举报
奈斯,感谢分享
回复 使用道具 举报
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马