
В простейшем случае для запуска 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.
