В простейшем случае для запуска Activity в Android нужно создать Intent c указанием класса вызываемого activity и Bundle из параметров. И всё хорошо, пока у нас в приложении пара экранов. Сложности начинаются тогда, когда количество экранов в нашем приложении будет исчисляться десятками. В данной статье я бы хотел предложить относительно несложный способ организации работы с большим количеством Activity.
Введение
Для того, что бы разговор был более предметным, будем считать, что в нашем приложении есть по крайней мере 3 активити:
- Список документов DocumentsList. Может запускаться либо без параметров для вывода всех документов, либо с параметром int categoryId для вывода документов из данной категории;
- Просмотр документа DocumentView. Вызывается только с параметром UUID documentId для просмотра существующего документа;
- Редактор документа DocumentEdit. Вызывается без параметра для создания нового документа или с параметром UUID documentId для редактирования уже существующего документа.
Проблема
Что является главным недостатком стандартного подхода, при котором экземпляры Intent создаются прямо в коде Activity. Это дублирование кода. Если мы захотим добавить к вызову активити ещё один параметр, нам придётся изменить все места, где это активити вызывается. Если приложение разрабатывается более чем одним человеком, то придётся оповестить всю команду о сделанных изменениях. Если потребуется заменить одно активити другим, потребуется опять-таки искать все вхождения. И пускай такую работу за нас может выполнить IDE, все равно это не фен-шуй.
Решение
Итак, хотелось бы получить некий объект, позволяющий:
- вызывать активити без явного указания класса вызываемого активити и без явного создания Intent;
- подменить одно активити другим;
- изменить параметры вызова существющего активити.
Под это описание подходит паттерн mediator. Теперь дело за реализацией.
Реализация
Диаграмма классов приведена в начале статьи. Сначала рассмотрим каждый из классов подробнее.
Класс MyIntent хранит константы для параметров вызова activity.
public class MyIntent extends Intent {
public static final String EXTRA_CATEGORY_ID = "CategoryId";
public static final String EXTRA_DOCUMENT_ID = "DocumentId";
}
Класс ActivityMediator реализует вывоз активити по данному классу. Конструктор принимает текущее активити и сохраняет в приватное поле. Два защищённых метода вызывают активити по данному классу без экстра или с ним. Защищёнными эти методы сделаны для того, что бы избежать соблазна вызывать их напрямую.
public class ActivityMediator {
private Activity mActivity;
public ActivityMediator(Activity activity){
mActivity = activity;
}
protected void startActivity(Class<?> cls){
Intent intent = new Intent(mActivity, cls);
mActivity.startActivity(intent);
}
protected void startActivity(Class<?> cls, Bundle extras){
Intent intent = new Intent(mActivity, cls);
intent.replaceExtras(extras);
mActivity.startActivity(intent);
}
}
От класса ActivityMediator наследуем класс MyActivityMediator.
public class MyActivityMediator extends ActivityMediator {
public MyActivityMediator(Activity activity){
super(activity);
}
public void showDocumentsList(){
startActivity(DocumentsListActivity.class);
}
public void showDocumentsList(int categoryId){
Bundle bundle = new Bundle();
bundle.putInt(MyIntent.EXTRA_CATEGORY_ID, categoryId);
startActivity(DocumentsListActivity.class, bundle);
}
public void showDocumentViewer(UUID documentId){
Bundle bundle = new Bundle();
bundle.putString(MyIntent.EXTRA_DOCUMENT_ID, documentId.toString());
startActivity(DocumentViewActivity.class, bundle);
}
public void showDocumentEditor(){
startActivity(DocumentEditActivity.class);
}
public void showDocumentEditor(UUID documentId){
Bundle bundle = new Bundle();
bundle.putString(MyIntent.EXTRA_DOCUMENT_ID, documentId.toString());
startActivity(DocumentEditActivity.class, bundle);
}
}
Класс MyActivity — абстрактный, от него наследуются все остальные активити в проекте.
public abstract class MyActivity extends Activity {
private KadActivityMediator mActivityMediator = new KadActivityMediator(this);
public KadActivityMediator getActivityMediator(){
return mActivityMediator;
}
}
Теперь в любом активити нашего приложения мы можем вызвать любое другое активити. Например, так можно вызвать редактор для создания нового документа:
getActivityMediator().showDocumentEditor();
а так — просмотр выбранного документа
UUID documentId = getCurrentDocumentId();
getActivityMediator().showDocumentViewer(documentId);
Заключение
В данной статье был дан пример использования паттерна mediator для организации работы со множеством activity в ОС Android. Развивая данную мысль, можно добавить вызовы startActivityForResult или вызов активити на основе action.