Комментарии 29
Подход здравый. Парочка замечаний:
1. Зачем нужно разделение на ActivityMediator и MyActivityMediator? Неужели нельзя было одним классом обойтись? И назвать его как-то получше, чтобы в имени не отражались детали реализации(паттерн), скажем ActivityLauncher?
2. Зачем вы специализируете ссылку на контекст классом Activity? А если вы захотите из сервиса активити вызывать? Менять же придется. У вас уже есть интерфейс Context, используйте его.
3. Чекстайл-онли: что за манера писать члены класса с префиксом m? Ну любая среда разработки подкрашивает члены класса, зачем это надо?
1. Зачем нужно разделение на ActivityMediator и MyActivityMediator? Неужели нельзя было одним классом обойтись? И назвать его как-то получше, чтобы в имени не отражались детали реализации(паттерн), скажем ActivityLauncher?
2. Зачем вы специализируете ссылку на контекст классом Activity? А если вы захотите из сервиса активити вызывать? Менять же придется. У вас уже есть интерфейс Context, используйте его.
3. Чекстайл-онли: что за манера писать члены класса с префиксом m? Ну любая среда разработки подкрашивает члены класса, зачем это надо?
Нормальные вопросы, спасибо.
1) ActivityMediator я использую в нескольких проектах, он у меня вынесен в библиотеку. Отсюда и разделение. Название с упоминанием имени паттерна мне кажется логичнее, так как соответсвует принципу наименьшего удивления — видишь в названии слова Activity и Mediator и уже примерно понимаешь, что класс будет делать.
2) Да, можно было и просто Context использовать. Но у Activity есть метод startActivityForResult. Я здесь выложил не все исходники, только необходимый минимум что бы показать суть. В реальном ActivityMediator у меня около десятка методов. В данном случае да, вы правы, можно было обойтись Context
3) source.android.com/source/code-style.html «Non-public, non-static field names start with m.»
1) ActivityMediator я использую в нескольких проектах, он у меня вынесен в библиотеку. Отсюда и разделение. Название с упоминанием имени паттерна мне кажется логичнее, так как соответсвует принципу наименьшего удивления — видишь в названии слова Activity и Mediator и уже примерно понимаешь, что класс будет делать.
2) Да, можно было и просто Context использовать. Но у Activity есть метод startActivityForResult. Я здесь выложил не все исходники, только необходимый минимум что бы показать суть. В реальном ActivityMediator у меня около десятка методов. В данном случае да, вы правы, можно было обойтись Context
3) source.android.com/source/code-style.html «Non-public, non-static field names start with m.»
1) В том-то и дело, что класс сразу говорит: внутри я устроен так-то. А должен говорить — какая разница тебе, как я устроен, я просто запускаю нужные активити!
2) с этим согласен, да, startActivityForResult все портит.
2) с этим согласен, да, startActivityForResult все портит.
Ага, я понял вашу мысль. Я привык к именно такому стилю именования классов, что бы понятно было не только что он делает, но и как. Например, всем известный StringBuilder — паттерн Builder, в Spring Framework есть ClientHttpRequestFactory — паттерн абстрактная фабрика, в MIDP реализации паттерна комманда назывались FooCommand и тд. Но синглтоны почему-то никогда постфиксом не обозначаются…
В общем, я привык к такому подходу, и пока проблем от этого не получил. Если проблемы возникнут, я поменяю подход.
В общем, я привык к такому подходу, и пока проблем от этого не получил. Если проблемы возникнут, я поменяю подход.
про 2. возможно стоит подумать про IntentFactory всесто ActivityMediator'а? Решит вопрос и со startActivityForResult и с уведомлениями и др.
Можно взглянуть на полную верию ActivityMediator?
Был опыт использования подобного подхода. На практике оказалось довольно муторно если взять чуть влево/вправо (управление стеком активити, наследование только от супер-активити).
Наблюдал подобный подход в приложенииGoogle IO в классе ActivityHelper, только там этот класс еще и ActionBar устанавливал.
Собственно в своих проектах тоже этим подходом пользуюсь и для ActionBar и для взаимодействия между активити, очень удобно.
Собственно в своих проектах тоже этим подходом пользуюсь и для ActionBar и для взаимодействия между активити, очень удобно.
Не совсем по теме, но интересно обсудить вопрос. Подход с MyActivity классом бывает полезным во многих ситуациях. Но он спотыкается об TabActivity, MapActivity… Интересно как народ выходит из положения? Придумал ли ктото чтото более умное чем использование MyActivity где можно и копирование его содержимого там где базовый класс другой?
можно решить эту проблему, если пользоваться фрагментами.
А так мне пару месяцев назад пришлось городить костыль в виде TabbedMapActivity класса, наследовавшегося от TabActivity и реализующего функционал MapActivity :)
А так мне пару месяцев назад пришлось городить костыль в виде TabbedMapActivity класса, наследовавшегося от TabActivity и реализующего функционал MapActivity :)
А почему не MapActivity как одна из табов TabActivity?
А вообще Android SDK навевает устойчивую мысль о споре про множественное наследование.
А вообще Android SDK навевает устойчивую мысль о споре про множественное наследование.
в том проекте у меня был UI со вложенными табами. И вот во второе вложенное TabActivity необходимо было добавить MapView. Большой уровень вложенности активити время от времени вызывал стаковерфлов, поэтому пришлось городить подобный костыль.
Вроде как с переходом на фрагменты ситуация улучшается. MapFragment, TabFragment гораздо проще использовать.
Вроде как с переходом на фрагменты ситуация улучшается. MapFragment, TabFragment гораздо проще использовать.
Да это проблема, тут сразу всплыла мысль про trait из Scala/Kotlin. Просто расширяем trait'ом любой класс Activity и получаем функционал.
p.s. потихоньку, но уверенно отхожу от Java для Android. Правда никакого production, увы.
p.s. потихоньку, но уверенно отхожу от Java для Android. Правда никакого production, увы.
очень интересно. а вы не могли бы вы поподробнее, как вы на scala под андроид пишите?
Ну Scala, крута, только время сборки очень медленное. Там в принципе нужно в Eclipse скачать версию ниже 2.9 Scala + TreeShacker для отрезания кусков ненужных из Scala runtime. Да собственно и все, все делаеться в Eclipse кликами. Сейчас смотрю на Kotlin, его можно установить в IDEA и там же сразу без всяких проблем запускать на Android. Что интересно, как и предъявлено в документации языка, сборка практически не заметна, как и Java, что дает огромный плюс в сторону Kotlin, а не Scala. Ради этого так же стартанул проект github.com/vladlichonos/kotlinAndroidLib чтобы обвернуть все Android и сделать чтобы было легко использовать :)
А почему ActivityMediator не сделан синглтоном? В представленной реализации, имхо, медиатор слишком сильно привязывается к Activity и к MyActivity в частности. Можно было бы преспокойно сделать его синглтоном, с конструктором без параметров, а каждый вызов showDocumentViewer() и др. дополнительно параметризовать Context'ом. На один параметр больше, зато — полная независимость от MyActivity, TabActivity и проч…
ну вообще я уверен, что если синглтон с конекстом, то это явный признак того, что-то мы неправильно сделали с точки зрения архитектуры
1) если хранить постоянную ссылку на контекст, то получим утечку памяти
2) если сувать контекст параметром к каждому методу, то мы сделаем маленький шажок к говнокоду. Роберт Мартин писал, что такого рода параметры — плохо. а у меня нет оснований ему не верить))
1) если хранить постоянную ссылку на контекст, то получим утечку памяти
2) если сувать контекст параметром к каждому методу, то мы сделаем маленький шажок к говнокоду. Роберт Мартин писал, что такого рода параметры — плохо. а у меня нет оснований ему не верить))
В своем проекте с небольшим числом Активити использовал простой статический класс.
По сути, использование в коде ничем не отличается от предложенного в статье — только первый параметр будет this. Ну и намного проще в реализации :) Наверно фанаты паттернов иронично ухмыльнутся, а фанаты KISS согласятся :)
Пример:
Director.goTrainList(this, 100);
По сути, использование в коде ничем не отличается от предложенного в статье — только первый параметр будет this. Ну и намного проще в реализации :) Наверно фанаты паттернов иронично ухмыльнутся, а фанаты KISS согласятся :)
Пример:
Director.goTrainList(this, 100);
public class Director {
public static void goHome(Activity activity) {
activity.startActivity(new Intent(activity, MainActivity.class));
}
public static void goWordList(Activity activity) {
activity.startActivity(new Intent(activity, WordListActivity.class));
}
public static void goTrainList(Activity activity, int dicId) {
Intent intent = new Intent(activity, TrainListActivity.class);
intent.putExtra(TrainListActivity.TrainDicId, dicId);
activity.startActivity(intent);
}
}
использование паттернов не противоречит kiss
я уже сто раз убеждался, что понятия «просто», «правильно» и «работает» чаще всего появляются вместе.
я уже сто раз убеждался, что понятия «просто», «правильно» и «работает» чаще всего появляются вместе.
Это верно.
Скажите, в чем преимущество вашего метода над моим, в данном контексте?
(Вопрос не ради поспорить а ради опыта)
Скажите, в чем преимущество вашего метода над моим, в данном контексте?
(Вопрос не ради поспорить а ради опыта)
Существенных преимуществ ни в том, ни в другом я на вскидку не вижу. По сути, у вас тот же медиатор, только статичный.
Давайте опишу несущественные. У вас:
— на 1 параметр больше в каждом методе
— дублируется код создания интента
У меня:
— нужно все активити от одного наследовать
— непонятно (как писали выше) как вызывать активити из сервиса (возможно, писать свой абстрактный класс от Service)
Давайте опишу несущественные. У вас:
— на 1 параметр больше в каждом методе
— дублируется код создания интента
У меня:
— нужно все активити от одного наследовать
— непонятно (как писали выше) как вызывать активити из сервиса (возможно, писать свой абстрактный класс от Service)
Существенных преимуществ ни в том, ни в другом я на вскидку не вижу. По сути, у вас тот же медиатор, только статичный.
Давайте опишу несущественные. У вас:
— на 1 параметр больше в каждом методе
— дублируется код создания интента
У меня:
— нужно все активити от одного наследовать
— непонятно (как писали выше) как вызывать активити из сервиса (возможно, писать свой абстрактный класс от Service)
Давайте опишу несущественные. У вас:
— на 1 параметр больше в каждом методе
— дублируется код создания интента
У меня:
— нужно все активити от одного наследовать
— непонятно (как писали выше) как вызывать активити из сервиса (возможно, писать свой абстрактный класс от Service)
сори, это был ответ на habrahabr.ru/blogs/android_development/131579/#comment_4376072
Почему бы для вызова активити из сервиса не расширить реализацию медиаторов следующим образом:
Дальше, соответственно:
public class ContextMediator
{
// -- construction
public ContextMediator(Context context) {
mContext = context;
}
// -- properties
protected Context getContext() {
return mContext;
}
// -- functions
protected void startActivity(Class<?> cls)
{
Intent intent = new Intent(mContext, cls);
mContext.startActivity(intent);
}
protected void startActivity(Class<?> cls, Bundle extras)
{
Intent intent = new Intent(mContext, cls);
intent.replaceExtras(extras);
mContext.startActivity(intent);
}
// -- variables
private final Context mContext;
}
public class ActivityMediator extends ContextMediator
{
// -- construction
public ActivityMediator(Activity activity) {
super(activity);
}
// -- properties
protected Activity getActivity() {
return (Activity) getContext();
}
// -- functions
protected void startActivityForResult(Class<?> cls, int requestCode)
{
Intent intent = new Intent(getActivity(), cls);
getActivity().startActivityForResult(intent, requestCode);
}
}
Дальше, соответственно:
public abstract class MyActivity extends Activity {
private ActivityMediator mActivityMediator = new ActivityMediator(this);
public ActivityMediator getActivityMediator(){
return mActivityMediator;
}
}
public abstract class MyService extends Service {
private ContextMediator mContextMediator = new ContextMediator(this);
public ContextMediator getActivityMediator() {
return mContextMediator;
}
}
С своем коде взял за правило в каждом активити, которое можно можно запустить с параметрами, иметь статический метод который и создает интент для запуска этого активити.
1. Каждый далее пользуется интентом как хочет
2. У каждого активити знаешь, где искать лаунчер.
Медиатор при количестве активити в проекте более 10 (каждое в несколькими вариантами запуска), как мне кажется, будет перегружен.
Все параметры активити известны только ему (private).
1. Каждый далее пользуется интентом как хочет
2. У каждого активити знаешь, где искать лаунчер.
Медиатор при количестве активити в проекте более 10 (каждое в несколькими вариантами запуска), как мне кажется, будет перегружен.
Все параметры активити известны только ему (private).
кстати да, клёвое решение
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Использование паттерна mediator для переключения между activity