Услышав об аспектно ориентированном программировании я, как Android разработчик, сразу подумал, что на Android это вряд ли заработает, однако, решил попробовать. Я был очень удивлен, когда уже через 5 минут приложение, использующее AspectJ, успешно заработало на телефоне.
Не буду убеждать в необходимости использования аспектов в Android и приводить примеры «uses cases», просто приведу пример того, как добавить к своему приложению возможность использования аспектов. Что такое аспекты и для чего их использовать прекрасно описано, например, на wiki.
В качестве IDE для разработки я уже давно перешел на Android Studio, а следовательно использую gradle как систему сборки. Для нее и буду приводить пример конфигурирования.
Весь процесс подключения AspectJ состоит из следующих шагов:
- Подключаем плагин для сборки:
В разделеbuildscript
скрипта сборки вашего проекта добавляем вdependencies
строку:classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+'
- В
build.gradle
модуля приложения добавляем:apply plugin: "android-aspectj"
- … а в зависимости модуля добавляем:
dependencies { compile 'org.aspectj:aspectjrt:1.8.+' }
- Пишем сам аспект.
Аспекты можно писать, используя специальный синтаксис, в файлах с расширением as, либо используя java + ряд анотаций. Поскольку Android Studio не включает AspectJ плагин, то я предпочел второй вариант (Для обладателей Ultimate версии IDEA доступны оба варианта):@Aspect public class MainActivityAspect { private static final String TAG = "helloaspectj"; @Pointcut("execution(* ru.hoticecream.helloaspectj.ui.MainActivity.onCreate(..))") public void onCreateMethod(){} @Before("onCreateMethod()") public void doBeforeOnCreate(JoinPoint joinPoint) { Log.i(TAG, "AspectJ was here"); } }
Данный аспект встраивается до вызова метода
MainActivity.onCreate
, выводя соответствующее сообщение в лог.
Теперь, запустив приложение и открыв MainActivity, мы увидим в логе:
... I/helloaspectj﹕ AspectJ was here
Приведу еще пример использования аспекта.
Для этого в MainActivity добавим метод, устанавливающий определенному текстовому полю сообщение:
private TextView mGreetingText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGreetingText = (TextView) findViewById(R.id.greeting_message);
setGreetingMessage("Hello Android");
}
private void setGreetingMessage(String message) {
mGreetingText.setText(message);
}
Как видите, поле принимает значение «Hello Android», запустив приложение можно в этом убедиться;)
Теперь добавим все в тот же класс аспекта следующие методы:
@Pointcut("execution(* ru.hoticecream.helloaspectj.ui.MainActivity.setGreetingMessage(..))")
public void setGreetingMessageMethod(){}
@Around("setGreetingMessageMethod()")
public void makeNasty(final ProceedingJoinPoint pjp)
throws Throwable {
Log.d(TAG, pjp.getSignature().toLongString());
pjp.proceed(new Object[] { "Hello AspectJ" });
}
В теперь этот аспект еще ищет метод setGreetingMessage
и заменяет его вызов на содержимое метода makeNasty</nasty>, используя для этого анотацию <code>@Around
Запустив приложение, мы уже увидим «Hello AspectJ». При этом MainActivity.java
мы не изменяли.
На этом все. Надеюсь статья была вам полезна.
Напоследок пару ссылок:
- За то, что все было так просто стоит сказать спасибо автору плагина для gradle:
github.com/uPhyca/gradle-android-aspectj-plugin - Интересная лекция по AspectJ, рассказывающая о примерах использования и возможностях библиотеки:
www.youtube.com/watch?v=X_QJMKEgJBk&index=3&list=PLCA5CB42F5A816A17 - И наконец, исходники примера из данной статьи:
github.com/HotIceCream/helloaspectj
Автор: HotIceCream