[JAVA] Vous pouvez le faire avec une copie! Programmation orientée aspect (Android)

introduction

Par exemple, si vous souhaitez vous connecter au début et à la fin d'une méthode, est-il réaliste de l'écrire pour chaque méthode? En supposant que vous intégriez ce processus dans une méthode particulière pour mesurer le temps de traitement pour la mesure des performances, souhaitez-vous modifier votre code pour cela? Les deux sont non, non? La programmation orientée aspect fournit un moyen "relativement simple" de les résoudre. En incorporant cela, vous pouvez vous concentrer sur chaque intérêt.

J'ai cherché divers articles, mais je n'ai pas trouvé un article écrit en japonais, donc [ici](https://fernandocejas.com/2014/08/03/aspect-oriented-programming- Rédigez un article basé sur in-android /). Fondamentalement, le code suit la page de référence.

Programmation orientée aspect

Je vais omettre la question de savoir ce qu'est la programmation orientée aspect. Veuillez vous référer à d'autres articles et littérature pour le contenu et les termes académiques.

Procédure d'installation

De là, j'expliquerai la procédure pour faire quelque chose qui fonctionne concrètement.

Avant cela, cet article vous amènera à inclure le code source dans votre projet. Si vous souhaitez le découper comme un autre projet et l'ajouter au projet en tant que bibliothèque, veuillez le lire comme il convient. Je pense que la seule chose que vous devez lire est de réécrire build.gradle.

Je vais expliquer les deux méthodes suivantes pour cela.

  1. Comment utiliser le plug-in
  2. Comment utiliser AspectJ live

Le premier utilise également AspectJ, mais le plug-in fait les réglages fastidieux pour vous. Par conséquent, il est facile à configurer. Ce dernier utilise AspectJ tel quel, vous devez donc écrire le processus à construire dans app / build.gradle pour construire.

Création de marque

Tout d'abord, faites une marque pour interrompre le processus. Le repère est une annotation.

DebugTraceBefore.java


@Retention(RetentionPolicy.CLASS)
@Target({ ElementType.METHOD })
public @interface DebugTraceBefore {}

DebugTraceAround.java


@Retention(RetentionPolicy.CLASS)
@Target({ ElementType.METHOD })
public @interface DebugTraceAround {}

Veuillez vous référer à un autre article pour la conservation et la cible des annotations.

Nous avons préparé deux types de points de repère. debugtracebeforeAvant la méthode qui a défini cette annotation, debugtracearoundPermet d'interrompre le traitement avant et après la méthode dans laquelle cette annotation est définie. Le nom de l'annotation est arbitraire.

Implémentation du traitement d'interruption

Ensuite, écrivez le type de traitement interrompu. Cette fois, j'écrirai le processus pour sortir le journal.

@aspectC'est une marque que le processus d'interruption par la programmation orientée aspect est écrit ici.

@pointcutMaintenant, définissez une marque pour interrompre le processus. Appelons la méthode avec cet ensemble d'annotations comme méthode de coupure par point </ b>.

@beforeOu@after@aroundIndique où interrompre le processus et spécifie la méthode de coupe ponctuelle à interrompre.

Le nom de la méthode est arbitraire, mais c'est une bonne idée de lui donner un nom descriptif.

DebugTraceBefore etc. sont des annotations, donc l'exécution(...)parmi@Est attaché.


 S'il s'agit d'une méthode de la classe spécifiée, elle peut être spécifiée comme ```execution (void android.app.Activity.onCreate (..)) `` `.

#### **`execution(...)Vous devez spécifier le nom complet du package pour.`**

AspectDebugLog.java


@Aspect
public final class AspectDebugLog {

    private static final String POINTCUT_BEFORE_METHOD =
            "execution(@com.test.aspectorientationprogrammingsample.aspect.DebugTraceBefore * *(..))";
    
    private static final String POINTCUT_AROUND_METHOD =
            "execution(@com.test.aspectorientationprogrammingsample.aspect.DebugTraceAround * *(..))";

    @Pointcut(POINTCUT_BEFORE_METHOD)
    public void pointcutDebugTraceBefore() {}

    @Pointcut(POINTCUT_AROUND_METHOD)
    public void pointcutDebugTraceAround() {}

    @Pointcut("execution(void android.app.Activity.onCreate(..))")
    public void pointcutOnCreate() {}

    @Before("pointcutOnCreate()")
    public void weavePreOnCreate(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String className = methodSignature.getDeclaringType().getSimpleName();

        Log.d("Aspect", "### weavePreOnCreate: " + className);
    }

    @After("pointcutOnCreate()")
    public void weavePostOnCreate(JoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String className = methodSignature.getDeclaringType().getSimpleName();

        Log.d("Aspect", "### weavePostOnCreate: " + className);
    }

    @Before("pointcutDebugTraceBefore()")
    public void weaveDebugTraceBefore(JoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String className = methodSignature.getDeclaringType().getSimpleName();
        String methodName = methodSignature.getName();

        Log.d("Aspect", "### weaveDebugTraceBefore: " + className + " " + methodName);
    }

    @Around("pointcutDebugTraceAround()")
    public Object weaveDebugTraceAround(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String className = methodSignature.getDeclaringType().getSimpleName();
        String methodName = methodSignature.getName();

        Log.d("Aspect", "### weaveDebugTraceAround - start: " + className + " " + methodName);

        Object result = joinPoint.proceed();

        Log.d("Aspect", "### weaveDebugTraceAround - end: " + className + " " + methodName);

        return result;
    }
}

Création d'écran

Ensuite, créez un écran.

MainActivity.java



public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.button1).setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    @DebugTraceAround
                    public void onClick(View view) {
                        Log.d("Log", "### onClick: button1");
                    }
                });

        findViewById(R.id.button2).setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    @DebugTraceBefore
                    public void onClick(View view) {
                        Log.d("Log", "### onClick: button2");
                    }
                });

    }

//    @Override
//    public void onResume() {
//        super.onResume();
//    }

    @Override
    @DebugTraceBefore
    public void onPause() {
        super.onPause();
    }
}

C'est un écran avec seulement deux boutons.

onCreate(...)L'annotation créée cette fois n'est pas définie.


```onpause() ```Pour sortir le journal avant```debugtracebefore```Est spécifié.
 J'ai défini une annotation pour générer un journal même lorsque vous cliquez sur le bouton.

 C'est tout pour écrire du code Java.
 À partir de là, réécrivez build.gradle.

## Comment utiliser le plug-in

 Dans la méthode d'utilisation du plug-in, je présenterai un exemple d'utilisation de ceci.

[GradleAspectJ-Android](https://github.com/Archinamon/android-gradle-aspectj)


#### **`app/build.gradle`**
```gradle

//Ajouter à partir d'ici
buildscript {
    repositories {
        jcenter()
        mavenCentral()
        maven { url "https://jitpack.io" }
    }

    dependencies {
        classpath 'com.github.Archinamon:GradleAspectJ-Android:3.0.3'
    }
}
//Ajouter ici

apply plugin: 'com.android.application'
apply plugin: 'com.archinamon.aspectj'//ajouter à

android {
    compileSdkVersion 27
    buildToolsVersion "27.0.1"
    defaultConfig {
        applicationId "com.test.aspectorientationprogrammingsample"
        minSdkVersion 21
        targetSdkVersion 27
        versionCode 1
        versionName "1.0.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            multiDexEnabled true
            minifyEnabled true  // true:Brouiller(Il est nécessaire de définir des classes, des méthodes, etc. qui ne s'obscurcissent pas comme il convient.)、false:N'obscurcissez pas
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    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:27.+'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
}

Comment utiliser AspectJ live

Il y a quelques commentaires en cours de route, mais vous pouvez les supprimer.

app/build.gradle


//Ajouter à partir d'ici
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }

    dependencies {
        classpath 'org.aspectj:aspectjtools:1.8.1'
    }
}
//Ajouter ici

apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    buildToolsVersion "27.0.1"
    defaultConfig {
        applicationId "com.test.aspectorientationprogrammingsample"
        minSdkVersion 21
        targetSdkVersion 27
        versionCode 1
        versionName "1.0.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            multiDexEnabled true
            minifyEnabled true  // true:Brouiller(Il est nécessaire de définir des classes, des méthodes, etc. qui ne s'obscurcissent pas comme il convient.)、false:N'obscurcissez pas
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    //Ajouter à partir d'ici
    applicationVariants.all { variant ->
//        JavaCompile javaCompile = variant.javaCompile// use javaCompiler instead of javaCompile
//        javaCompile.doLast {
//            //
//        }

        variant.javaCompiler.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)]

            MessageHandler handler = new MessageHandler(true);
            new Main().run(args, handler)

            def log = project.logger
            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:
                    case IMessage.INFO:
                        log.info message.message, message.thrown
                        break;
                    case IMessage.DEBUG:
                        log.debug message.message, message.thrown
                        break;
                }
            }
        }
    }
    //Ajouter ici
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    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:27.+'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'

    compile 'org.aspectj:aspectjrt:1.8.1'//ajouter à
}

Courir

Lorsque vous faites cela, le journal sera généré comme suit: (Comme il devient difficile à lire, l'heure, etc. est supprimée.)

D/Aspect: ### weavePreOnCreate: MainActivity
D/Aspect: ### weavePostOnCreate: MainActivity
D/Aspect: ### weaveDebugTraceBefore: MainActivity onPause
D/Aspect: ### weaveDebugTraceAround - start:  onClick
D/Log: ### onClick: button1
D/Aspect: ### weaveDebugTraceAround - end:  onClick
D/Aspect: ### weaveDebugTraceBefore:  onClick
D/Log: ### onClick: button2

à la fin

J'ai également confirmé que cela fonctionne dans mon environnement, mais comment était-ce dans votre environnement? Cela a-t-il fonctionné?

Un point à noter est que execution (void android.app.Activity.onCreate (..)) `` `` peut être changé en execution (void android.app.Activity.onResume ()) Aucun journal n'est sorti. Parce que MyActivity ne remplace pas onResume. Les journaux des méthodes non implémentées ne sont pas générés. C'est naturel.

Maintenant, vous pouvez supprimer la logique supplémentaire!

Appendix

environnement

Nous avons confirmé l'opération dans l'environnement suivant.

environnement version
Mac OS Sierra 10.12.6
Android Studio 2.3.3
Java version 8
Gradle version 3.3
Android Plugin version 2.3.3

Recommended Posts

Vous pouvez le faire avec une copie! Programmation orientée aspect (Android)
Pouvez-vous le faire? Java EE
Base de données Firebase-Realtime sur Android pouvant être utilisée avec copie
Vous pouvez tout faire avec votre smartphone ou tablette Android! Résumé d'Arekore pour déménager avec Termux
Si vous vous en souvenez, vous pouvez le gérer. Mise en page automatique écrite avec du code
La fin de la programmation catastrophique # 01 "Faites-le avec la valeur absolue d'un entier"
[Android Studio] Si vous pensez ne pas trouver la dernière bibliothèque d'assistance
Vous pouvez le faire tout de suite avec Serverless Framework Serverless with AWS (API + Lambda [java] est facile à configurer)
[Bonne nouvelle] Vous pouvez toujours utiliser Java 8 !!
Avec Tomcat, vous pouvez utiliser des espaces réservés ($ {...}) dans web.xml.
Vous pouvez éliminer @Param avec Kotlin 1.1 et MyBatis 3.4.1+! !!