[JAVA] Sie können es mit Kopie tun! Aspektorientierte Programmierung (Android)

Einführung

Wenn Sie beispielsweise am Anfang und am Ende einer Methode protokollieren möchten, ist es realistisch, sie für jede Methode zu schreiben? Möchten Sie diesen Prozess in eine bestimmte Methode einbetten, um die Verarbeitungszeit für die Leistungsmessung zu messen und Ihren Code dafür zu ändern? Beide sind Nein, nicht wahr? Aspektorientierte Programmierung bietet eine "relativ einfache" Möglichkeit, sie zu lösen. Indem Sie dies einbeziehen, können Sie sich auf jedes Interesse konzentrieren.

Ich habe nach verschiedenen Artikeln gesucht, aber ich konnte keinen Artikel finden, der auf Japanisch geschrieben wurde, also [hier](https://fernandocejas.com/2014/08/03/aspect-oriented-programming- Schreibe einen Artikel basierend auf in-android /). Grundsätzlich folgt der Code der Referenzseite.

Aspektorientierte Programmierung

Ich werde die Frage weglassen, was aspektorientierte Programmierung ist. Weitere wissenschaftliche Inhalte und Begriffe finden Sie in anderen Artikeln und in der Literatur.

Installationsverfahren

Von hier aus erkläre ich das Verfahren, um etwas zu machen, das konkret funktioniert.

Zuvor werden Sie in diesem Artikel aufgefordert, den Quellcode in Ihr Projekt aufzunehmen. Wenn Sie es als anderes Projekt ausschneiden und als Bibliothek zum Projekt hinzufügen möchten, lesen Sie es bitte entsprechend. Ich denke, das einzige, was Sie lesen müssen, ist build.gradle neu zu schreiben.

Ich werde die folgenden zwei Methoden dafür erklären.

  1. Verwendung des Plug-Ins
  2. Verwendung von AspectJ live

Ersteres verwendet auch AspectJ, aber das Plug-In übernimmt die mühsamen Einstellungen für Sie. Daher ist es einfach einzurichten. Letzterer verwendet AspectJ so wie es ist, daher müssen Sie den Prozess zum Erstellen in app / build.gradle schreiben, um ihn zu erstellen.

Markieren Sie die Erstellung

Markieren Sie zunächst, um den Vorgang zu unterbrechen. Das Wahrzeichen ist eine Anmerkung.

DebugTraceBefore.java


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

DebugTraceAround.java


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

Weitere Informationen zur Aufbewahrung und zum Ziel von Anmerkungen finden Sie in einem anderen Artikel.

Wir haben zwei Arten von Sehenswürdigkeiten vorbereitet. debugtracebeforeVor der Methode, mit der diese Anmerkung festgelegt wurde, debugtracearoundErmöglicht die Unterbrechung der Verarbeitung vor und nach der Methode, in der diese Anmerkung festgelegt ist. Der Name der Anmerkung ist beliebig.

Implementierung der Verarbeitung unterbrechen

Schreiben Sie als Nächstes, welche Art der Verarbeitung unterbrochen ist. Dieses Mal werde ich den Prozess schreiben, um das Protokoll auszugeben.

@aspectIst ein Zeichen dafür, dass hier der Prozess der Unterbrechung durch aspektorientierte Programmierung geschrieben ist.

@pointcutSetzen Sie nun eine Markierung, um den Vorgang zu unterbrechen. Rufen wir die Methode mit dieser Annotation als Punktschnittmethode </ b> auf.

@beforeOder@after@aroundGibt an, wo der Prozess unterbrochen werden soll, und gibt an, welche Pointcut-Methode unterbrochen werden soll.

Der Methodenname ist willkürlich, aber es ist eine gute Idee, ihm einen beschreibenden Namen zu geben.

DebugTraceBefore usw. sind Anmerkungen, also Ausführung(...)unter@Es ist angehängt.


 Wenn es sich um eine Methode der angegebenen Klasse handelt, kann sie als `` `Ausführung (void android.app.Activity.onCreate (..))` `angegeben werden.

#### **`execution(...)Sie müssen den vollständigen Paketnamen für angeben.`**

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;
    }
}

Bildschirmerstellung

Erstellen Sie als Nächstes einen Bildschirm.

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();
    }
}

Es ist ein Bildschirm mit nur zwei Tasten.

onCreate(...)Die diesmal erstellte Anmerkung ist nicht festgelegt.


```onpause() ```Um das Protokoll vorher auszugeben```debugtracebefore```Angegeben.
 Ich habe eine Anmerkung festgelegt, um ein Protokoll auszugeben, auch wenn auf die Schaltfläche geklickt wird.

 Das war's zum Schreiben von Java-Code.
 Von hier aus schreiben Sie build.gradle neu.

## So verwenden Sie das Plug-In

 In der Methode zur Verwendung des Plug-Ins werde ich ein Beispiel für die Verwendung dieses Plug-Ins vorstellen.

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


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

//Von hier aus hinzufügen
buildscript {
    repositories {
        jcenter()
        mavenCentral()
        maven { url "https://jitpack.io" }
    }

    dependencies {
        classpath 'com.github.Archinamon:GradleAspectJ-Android:3.0.3'
    }
}
//Addiere hier

apply plugin: 'com.android.application'
apply plugin: 'com.archinamon.aspectj'//hinzufügen

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:Verschleiert(Es ist erforderlich, Klassen, Methoden usw. festzulegen, die nicht entsprechend verschleiert werden.)、false:Nicht verschleiern
            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'
}

So verwenden Sie AspectJ live

Es gibt einige Kommentare auf dem Weg, aber es ist in Ordnung, sie zu löschen.

app/build.gradle


//Von hier aus hinzufügen
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'
    }
}
//Addiere hier

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:Verschleiert(Es ist erforderlich, Klassen, Methoden usw. festzulegen, die nicht entsprechend verschleiert werden.)、false:Nicht verschleiern
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    //Von hier aus hinzufügen
    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;
                }
            }
        }
    }
    //Addiere hier
}

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'//hinzufügen
}

Lauf

Wenn Sie dies tun, wird das Protokoll wie folgt ausgegeben: (Da das Lesen schwierig wird, werden Zeit usw. gelöscht.)

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

schließlich

Ich habe auch bestätigt, dass es in meiner Umgebung funktioniert, aber wie war es in Ihrer Umgebung? Hat es funktioniert?

Ein zu beachtender Punkt ist, dass `Ausführung (void android.app.Activity.onCreate (..))` `in` Ausführung (void android.app.Activity.onResume ()) `` geändert werden kann Es wird kein Protokoll ausgegeben. Weil MyActivity onResume nicht überschreibt. Protokolle nicht implementierter Methoden werden nicht ausgegeben. Es ist natürlich.

Jetzt können Sie die zusätzliche Logik ausschneiden!

Appendix

Umgebung

Wir haben den Betrieb in der folgenden Umgebung bestätigt.

Umgebung Ausführung
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

Sie können es mit Kopie tun! Aspektorientierte Programmierung (Android)
Kannst du es machen? Java EE
Firebase-Realtime-Datenbank für Android, die mit Kopie verwendet werden kann
Sie können alles mit Ihrem Android-Smartphone oder -Tablet tun! Zusammenfassung von Arekore, um mit Termux zu ziehen
Wenn Sie sich so gut erinnern, können Sie es verwalten. AutoLayout mit Code geschrieben
Das Ende der katastrophalen Programmierung # 01 "Mach es mit dem absoluten Wert einer ganzen Zahl"
[Android Studio] Wenn Sie der Meinung sind, dass Sie die neueste Support-Bibliothek nicht finden können
Sie können dies sofort mit Serverless Framework Serverless mit AWS tun (API + Lambda [Java] ist einfach einzurichten).
[Gute Nachrichten] Sie können immer noch mit Java 8 gehen !!
Mit Tomcat können Sie Platzhalter ($ {...}) in web.xml verwenden.
Sie können @Param mit Kotlin 1.1 und MyBatis 3.4.1+ eliminieren! !!