Синглтоны против контекста приложения в Android? - PullRequest
359 голосов
/ 30 сентября 2010

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

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

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

РЕДАКТИРОВАТЬ: Я хотел бы иметь мнения по нескольким аспектам:

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

Ответы [ 10 ]

292 голосов
/ 08 октября 2010

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

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

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

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

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

227 голосов
/ 30 сентября 2010

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

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

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

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

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

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

20 голосов
/ 23 марта 2012

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

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

11 голосов
/ 05 октября 2010

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

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

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

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

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

10 голосов
/ 26 марта 2014

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

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

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

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

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

4 голосов
/ 30 сентября 2010

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

3 голосов
/ 26 июля 2016

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

При разработке приложения может возникнуть необходимость в общем доступе к данным, контексту или службам по всему приложению. Например, если в вашем приложении есть данные сеанса, такие как текущий вошедший в систему пользователь, вы, вероятно, захотите предоставить эту информацию. В 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 голосов
/ 23 июня 2014

Мои 2 цента:

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

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

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

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

Надеюсь, это кому-нибудь поможет.

2 голосов
/ 24 апреля 2013

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...