it-swarm.com.ru

Синглтоны против контекста приложения в Android?

Вспоминая это пост, перечисляющий несколько проблем использования синглетонов и увидев несколько примеров Android приложений, использующих шаблон синглтона, я задаюсь вопросом, будет ли хорошей идеей использовать Singletons вместо отдельных экземпляров, совместно используемых через глобальное состояние приложения (создание подкласса Android.os.Application и получение его через context.getApplication ()).

Какие преимущества/недостатки будут иметь оба механизма?

Если честно, я ожидаю того же ответа в этом посте шаблон Singleton с веб-приложением, не очень хорошая идея! , но применяется к Android. Я прав? Чем отличается DalvikVM от других?

Правка: Я хотел бы иметь мнения по нескольким аспектам, связанным с:

  • Синхронизация
  • Повторное использование
  • Тестирование
356
mschonaker

Я очень не согласен с ответом Дайан Хакборн. Мы постепенно удаляем все синглтоны из нашего проекта в пользу легких объектов с областью задач, которые могут быть легко воссозданы, когда они вам действительно понадобятся.

Синглтоны - это кошмар для тестирования и, если их лениво инициализировать, будут вводить "неопределенность состояния" с тонкими побочными эффектами (которые могут внезапно появиться при перемещении вызовов getInstance() из одной области в другую). Видимость упоминается как еще одна проблема, и поскольку синглтоны подразумевают "глобальный" (= случайный) доступ к общему состоянию, могут возникнуть незначительные ошибки, если они не синхронизированы должным образом в параллельных приложениях.

Я считаю это анти-паттерном, плохим объектно-ориентированным стилем, который по сути сводится к поддержанию глобального состояния.

Чтобы вернуться к вашему вопросу:

Хотя контекст приложения можно рассматривать как одиночный, он управляется каркасом и имеет четко определенный жизненный цикл , область действия и путь доступа. Поэтому я считаю, что если вам нужно управлять глобальным состоянием приложения, оно должно идти сюда, больше никуда. Для чего-то еще, переосмыслите, если вам действительно нужен одноэлементный объект, или если также можно было бы переписать ваш одноэлементный класс, чтобы вместо этого создать экземпляр small, short- живые объекты, которые выполняют задачу под рукой.

291
Matthias

Я очень рекомендую синглтоны. Если у вас есть синглтон, который нуждается в контексте, есть:

MySingleton.getInstance(Context c) {
    //
    // ... needing to create ...
    sInstance = new MySingleton(c.getApplicationContext());
}

Я предпочитаю одиночные, а не прикладные приложения, потому что это помогает сделать приложение намного более организованным и модульным - вместо того, чтобы иметь одно место, где необходимо поддерживать все ваше глобальное состояние в приложении, каждый отдельный элемент может позаботиться о себе сам. Также хорошо то, что синглтоны лениво инициализируются (по запросу) вместо того, чтобы вести вас по пути полной инициализации в Application.onCreate ().

В использовании синглетонов нет ничего плохого. Просто используйте их правильно, когда это имеет смысл. Фреймворк Android на самом деле имеет их много, чтобы поддерживать кеширование загруженных ресурсов для каждого процесса и другие подобные вещи.

Также для простых приложений многопоточность не становится проблемой для синглетонов, потому что все стандартные обратные вызовы приложения отправляются в основной поток процесса, поэтому многопоточность не будет возникать, если вы не представите ее явно через потоки или неявно путем публикации поставщика контента или службы IBinder для других процессов.

Просто задумайтесь о том, что вы делаете. :)

226
hackbod

От: Разработчик> Ссылка - Приложение

Обычно нет необходимости создавать подкласс Application. В большинстве случаев статические синглтоны могут предоставлять ту же функциональность более модульным способом. Если вашему синглтону необходим глобальный контекст (например, для регистрации широковещательных приемников), функции для его извлечения может быть задан контекст, который внутренне использует Context.getApplicationContext () при первом создании синглтона.

20
Somatik

У меня была такая же проблема: синглтон или сделать подкласс Android.os.Application?

Сначала я попробовал с Singleton, но мое приложение в какой-то момент звонит в браузер

Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));

и проблема в том, что, если у телефона недостаточно памяти, большинство ваших классов (даже синглтонов) очищаются, чтобы получить немного памяти, поэтому при возврате из браузера в мое приложение каждый раз происходит сбой.

Решение: поместить необходимые данные в подкласс класса Application.

11
JoséMi

Приложение не совпадает с Singleton. Причины:

  1. Метод приложения (например, onCreate) вызывается в потоке пользовательского интерфейса;
  2. метод синглтона может быть вызван в любом потоке;
  3. В методе "onCreate" приложения вы можете создать экземпляр Handler;
  4. Если синглтон выполняется в потоке без пользовательского интерфейса, вы не можете создать экземпляр Handler;
  5. Приложение имеет возможность управлять жизненным циклом действий в приложении. У него есть метод "registerActivityLifecycleCallbacks". Но у синглетонов нет такой возможности.
10
sunhang

Рассмотрим оба варианта одновременно:

  • наличие одноэлементных объектов в качестве статических экземпляров внутри классов.
  • наличие общего класса (Context), который возвращает единичные экземпляры для всех объектов singelton в вашем приложении, что имеет преимущество в том, что имена методов в Context будут иметь смысл, например: context.getLoggedinUser () вместо User.getInstance ().

Кроме того, я предлагаю вам расширить свой Контекст, включив в него не только доступ к одноэлементным объектам, но и некоторые функциональные возможности, к которым необходимо обращаться глобально, например: context.logOffUser (), context.readSavedData () и т.д. Вероятно, переименуйте Контекст в Фасад будет иметь смысл тогда.

5
adranale

Они на самом деле одинаковы. Есть одно отличие, которое я вижу. С помощью класса Application вы можете инициализировать свои переменные в Application.onCreate () и уничтожить их в Application.onTerminate (). С синглтоном вам нужно полагаться на VM инициализацию и уничтожение статики.

4
Fedor

Из уст пословиц лошади.

При разработке приложения может возникнуть необходимость в общем доступе к данным, контексту или службам по всему приложению. Например, если в вашем приложении есть данные сеанса, такие как текущий вошедший в систему пользователь, вы, вероятно, захотите предоставить эту информацию. В Android шаблон решения этой проблемы состоит в том, чтобы ваш экземпляр Android.app.Application владел всеми глобальными данными, а затем обрабатывал ваш экземпляр Application как одиночный объект со статическими средствами доступа к различным данным и службам.

При написании приложения Android вы гарантированно имеете только один экземпляр класса Android.app.Application, и поэтому безопасно (и рекомендуется командой Google Android) рассматривать его как одиночный , То есть вы можете безопасно добавить статический метод getInstance () в вашу реализацию приложения. Вот так:

public class AndroidApplication extends Application {

    private static AndroidApplication sInstance;

    public static AndroidApplication getInstance(){
        return sInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;
    }
}
3
RMcGuigan

Мои 2 цента:

Я заметил, что некоторые синглтон/статические поля были сброшены, когда моя деятельность была разрушена. Я заметил это на некоторых устройствах с низким уровнем 2.3.

Мой случай был очень прост: у меня просто есть закрытое поле "init_done" и статический метод "init", который я вызвал из activity.onCreate (). Я замечаю, что метод init повторно выполнял себя при некотором воссоздании действия.

Хотя я не могу доказать свое утверждение, оно может быть связано с тем, КОГДА синглтон/класс был создан/использован первым. Когда действие уничтожается/рециркулируется, кажется, что все классы, на которые ссылается только это действие, тоже перерабатываются.

Я переместил свой экземпляр singleton в подкласс Application. Я получаю доступ к ним из экземпляра приложения. и, с тех пор, не заметил проблемы снова.

Я надеюсь, что это может кому-то помочь.

3
Christ

Моя активность вызывает метод finish () (который не приводит к немедленному завершению, но в конечном итоге завершится) и вызывает Google Street Viewer. Когда я отлаживаю его в Eclipse, мое соединение с приложением разрывается, когда вызывается Street Viewer, что я понимаю как закрытое (целое) приложение, предположительно для освобождения памяти (так как одиночное завершающееся действие не должно вызывать такое поведение) , Тем не менее, я могу сохранить состояние в Bundle с помощью onSaveInstanceState () и восстановить его в методе onCreate () следующего действия в стеке. При использовании статического одноэлементного приложения или приложения подклассов я сталкиваюсь с состоянием закрытия и потери приложения (если я не сохраню его в Bundle). Так что из моего опыта они одинаковы в отношении сохранения государства. Я заметил, что соединение потеряно в Android 4.1.2 и 4.2.2, но не в 4.0.7 или 3.2.4, что в моем понимании предполагает, что механизм восстановления памяти изменился в какой-то момент.

2
Piovezan