目标:在执行特定方法后,使用AspectJ调用静态方法。
为了解决这个问题,让我们调用静态方法System.out.println
和方法onConfigurationChanged
。
约束:
onConfigurationChanged
方法(无法编织)*。onConfigurationChanged
在基类中有一个实现,子类可能会也可能不会覆盖它(但在System.out.println
执行onConfigurationChanged
之后仍应调用android.app.Activity
。“ / LI>
*注意:这是在构建Android应用程序的上下文中,因此所讨论的基类实际上是onConfigurationChanged
。很明显,编译时编织是不可能的。我已经研究了加载时编织,但是我不确定如何在这种情况下完成它,并且不确定我是否愿意,因为它是一个非常重要的代码路径。
我目前面临的主要问题是子类不会覆盖该方法的情况。
我尝试了什么:
使用@After
签名指定的执行切入点,其中定义了System.out.println
个建议,调用@After("execution(void com.jkhong..*.onConfigurationChanged()) "
+ "&& !within(DefaultOnConfigurationChangedAspect)")
public void onConfigurationChangedExecution() {
doDefaultOnConfigurationChanged();
}
private static void doDefaultOnConfigurationChanged() {
System.out.println("Default onConfigurationChanged (mixed in)");
}
。
onConfigurationChanged
以上适用于子类重写@DeclareMixin
方法的情况。
System.out.println
定位子类,返回一个调用onConfigurationChanged
的匿名类实现。返回的接口有一个方法,其签名与基类中的public interface OnConfigurationChangedListener {
void onConfigurationChanged();
}
@DeclareMixin("com.jkhong..*.*Activity")
public static OnConfigurationChangedListener createDefaultListener() {
return new OnConfigurationChangedListener() {
@Override
public void onConfigurationChanged() {
doDefaultOnConfigurationChanged();
}
};
}
完全相同。
onConfigurationChanged
不幸的是,上面没有将方面提供的onConfigurationChanged
实现添加到不覆盖OnConfigurationChangedListener
的子类。它确实指定子类实现<!-- saved from url=(0014)about:internet -->
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=8; IE=7; IE=EDGE" charset="utf-8">
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/themes/base/jquery-ui.css"></link>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
function displayData() {
$.get('http://www.w3schools.com/json/myTutorials.txt', function(responseText) {
alert(responseText);
});
}
</script>
</head>
<body>
<div id="menu">
<button type="button" id="btnDisplay" onclick="displayData()">Go</button>
</div>
</body>
</html>
接口,但由于该方法是在其父类中实现的,因此编译器不会抱怨。 (如果我略微调整接口方法的签名,以便它不再匹配,我看到它确实被添加了,但这不是理想的结果。)
非常感谢任何帮助,谢谢。
答案 0 :(得分:1)
出于技术原因,您必须使用原生语法,因为declare parents
比@DeclareParents
或@DeclareMixin
更强大。
Eclipse和IntelliJ IDEA都支持AspectJ本机语法。我不知道NetBeans。你使用哪个IDE?对于在Eclipse中找到的高级AspectJ语法功能的最佳支持,IDEA有一些缺点。但是无视语法突出显示,代码完成和重构等优秀功能,您可以在任何编辑器中编写方面。
至于你的问题,我想强调我不是Android开发人员,所以我只是重新创建了你使用这两个虚拟类的基本Android API功能,以使我的方面可测试:
将这些项目放入普通的Java项目中(或使用原始的Android API):
package android.app;
import android.content.res.Configuration;
public class Activity {
public void onConfigurationChanged (Configuration newConfig) {
System.out.println("onConfigurationChanged - default implementation");
}
}
package android.content.res;
public class Configuration {}
现在我们在IDE中创建另一个项目,这次是AspectJ项目。它应该引用上面的小虚拟Android API仿真。
在AspectJ项目中,我们为演示创建了两个Activity
子类,一个覆盖了onConfigurationChanged
,另一个没有覆盖它:
package com.jkhong.app;
import android.app.Activity;
import android.content.res.Configuration;
public class OverridingActivity extends Activity {
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
System.out.println("onConfigurationChanged - subclass override");
}
}
package com.jkhong.app;
import android.app.Activity;
public class NonOverridingActivity extends Activity {}
通过一个小的驱动程序应用程序,我们可以显示发生了什么:
package com.jkhong.app;
import android.app.Activity;
import android.content.res.Configuration;
public class Application {
public static void main(String[] args) {
Configuration newConfig = new Configuration();
System.out.println("Activity");
new Activity().onConfigurationChanged(newConfig);
System.out.println("\nOverridingActivity");
new OverridingActivity().onConfigurationChanged(newConfig);
System.out.println("\nNonOverridingActivity");
new NonOverridingActivity().onConfigurationChanged(newConfig);
}
}
控制台日志如下所示:
Activity
onConfigurationChanged - default implementation
OverridingActivity
onConfigurationChanged - default implementation
onConfigurationChanged - subclass override
NonOverridingActivity
onConfigurationChanged - default implementation
正如您所看到的,OverridingActivity
在执行任何其他操作之前调用其super
方法。我建议你一直这样做。对于NonOverridingActivity
,仅按预期执行基类的默认实现。
现在这是解决问题的方面:
package com.jkhong.aspect;
import android.app.Activity;
import android.content.res.Configuration;
public aspect ConfigurationChangeInterceptor {
public static class DefaultChangeListener extends Activity {
@Override
public void onConfigurationChanged (Configuration newConfig) {
super.onConfigurationChanged(newConfig);
doDefaultOnConfigurationChanged();
}
}
declare parents : Activity+ && !Activity extends DefaultChangeListener;
private static void doDefaultOnConfigurationChanged() {
System.out.println("onConfigurationChanged - aspect override");
}
}
请注意该方面如何使用Activity+ && !Activity
指定“所有Activity
子类但不指定Activity
本身”以避免编译器错误,因为Activity
无法扩展自身,并且无论如何都没有接触到织布工。
控制台日志现在如下所示:
Activity
onConfigurationChanged - default implementation
OverridingActivity
onConfigurationChanged - default implementation
onConfigurationChanged - aspect override
onConfigurationChanged - subclass override
NonOverridingActivity
onConfigurationChanged - default implementation
onConfigurationChanged - aspect override
所以现在你有你想要的东西。它为NonOverridingActivity
以及OverridingActivity
触发的日志输出。