Как объявить глобальные переменные в Android?

Я создаю приложение, которое требует входа в систему. Я создал основную активность и активность входа.

В методе main activity onCreate я добавил следующее условие:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    ...

    loadSettings();
    if(strSessionString == null)
    {
        login();
    }
    ...
}

Метод onActivityResult, который выполняется при завершении формы входа в систему, выглядит так:

@Override
public void onActivityResult(int requestCode,
                             int resultCode,
                             Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);
    switch(requestCode)
    {
        case(SHOW_SUBACTICITY_LOGIN):
        {
            if(resultCode == Activity.RESULT_OK)
            {

                strSessionString = data.getStringExtra(Login.SESSIONSTRING);
                connectionAvailable = true;
                strUsername = data.getStringExtra(Login.USERNAME);
            }
        }
    }

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

Кто-нибудь знает, как установить глобальную переменную, чтобы форма входа в систему не появлялась после того, как пользователь уже успешно прошел аутентификацию?


person Niko Gamulin    schedule 02.04.2009    source источник
comment
хороший учебник о том, как обрабатывать состояние активности с помощью пакета сохраненных состояний экземпляра quicktips.in/   -  person Deepak Swami    schedule 25.08.2015


Ответы (16)


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

ОРИГИНАЛЬНЫЙ ОТВЕТ:

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

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

Для этого нужно создать собственный подкласс android.app.Application, а затем укажите этот класс в теге приложения в своем манифесте. Теперь Android автоматически создаст экземпляр этого класса и сделает его доступным для всего вашего приложения. Вы можете получить к нему доступ из любого context, используя метод Context.getApplicationContext() (Activity также предоставляет метод getApplication(), который имеет точно такой же эффект). Ниже приведен чрезвычайно упрощенный пример с оговорками:

class MyApp extends Application {

  private String myState;

  public String getState(){
    return myState;
  }
  public void setState(String s){
    myState = s;
  }
}

class Blah extends Activity {

  @Override
  public void onCreate(Bundle b){
    ...
    MyApp appState = ((MyApp)getApplicationContext());
    String state = appState.getState();
    ...
  }
}

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

На что следует обратить внимание из приведенного выше примера; предположим, что вместо этого мы сделали что-то вроде:

class MyApp extends Application {

  private String myState = /* complicated and slow initialization */;

  public String getState(){
    return myState;
  }
}

Теперь эта медленная инициализация (например, попадание в диск, подключение к сети, блокирование чего-либо и т. Д.) Будет выполняться каждый раз при создании экземпляра приложения! Вы можете подумать, что это только один раз для процесса, и мне все равно придется оплатить стоимость, верно? Например, как упоминает ниже Дайан Хакборн, для вашего процесса вполне возможно создать экземпляр - просто - для обработки события фоновой широковещательной передачи. Если ваша широковещательная обработка не нуждается в этом состоянии, вы потенциально просто зря выполнили целую серию сложных и медленных операций. Ленивое создание экземпляров - вот название игры. Ниже приводится несколько более сложный способ использования Application, который имеет больше смысла для чего угодно, кроме простейшего использования:

class MyApp extends Application {

  private MyStateManager myStateManager = new MyStateManager();

  public MyStateManager getStateManager(){
    return myStateManager ;
  }
}

class MyStateManager {

  MyStateManager() {
    /* this should be fast */
  }

  String getState() {
    /* if necessary, perform blocking calls here */
    /* make sure to deal with any multithreading/synchronicity issues */

    ...

    return state;
  }
}

class Blah extends Activity {

  @Override
  public void onCreate(Bundle b){
    ...
    MyStateManager stateManager = ((MyApp)getApplicationContext()).getStateManager();
    String state = stateManager.getState();
    ...
  }
}

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

ПРИМЕЧАНИЕ 1: Также, как прокомментировал антикафе, для того, чтобы правильно привязать переопределение приложения к вашему приложению, в файле манифеста необходим тег. Опять же, см. Документацию по Android для получения дополнительной информации. Пример:

<application
     android:name="my.application.MyApp" 
     android:icon="..."
     android:label="...">
</application>

ПРИМЕЧАНИЕ 2: user608578 спрашивает ниже, как это работает с управлением жизненными циклами собственных объектов. Я ни в малейшей степени не разбираюсь в использовании нативного кода с Android, и я не могу ответить, как это будет взаимодействовать с моим решением. Если у кого-то есть ответ на этот вопрос, я готов отдать ему должное и помещу информацию в этот пост для максимальной наглядности.

ДОБАВЛЕНИЕ:

Как отмечали некоторые люди, это не решение для постоянного состояния, на что мне, возможно, следовало бы особо подчеркнуть в исходном ответе. Т.е. это не означает, что это решение для сохранения информации о пользователях или другой информации, которая должна сохраняться в течение всего времени жизни приложения. Таким образом, я считаю, что большая часть критики, приведенной ниже, в отношении приложений, которые могут быть убиты в любое время и т. Д., Спорна, поскольку все, что когда-либо требовалось сохранить на диске, не должно храниться через подкласс Application. Он предназначен для хранения временного, легко воспроизводимого состояния приложения (например, вошел ли пользователь в систему) и компонентов, которые являются одним экземпляром (например, диспетчер сети приложения) (НЕ одноэлементный !) в природе.

Дайерман любезно указал на интересный разговор с Рето Мейер и Дайанн Хакборн, в котором использование подклассов Application не рекомендуется в пользу шаблонов Singleton. Соматик также указывал на нечто подобное ранее, хотя в то время я этого не видел. Из-за роли Рето и Дайанны в поддержке платформы Android я не могу добросовестно рекомендовать игнорировать их советы. Что говорят, выходит. Я действительно хочу не согласиться с мнениями, выраженными в отношении предпочтения Singleton над подклассами Application. В моем несогласии я буду использовать концепции, лучше всего объясненные в этом объяснении StackExchange шаблона проектирования Singleton, чтобы В этом ответе мне не нужно определять термины. Я настоятельно рекомендую просмотреть ссылку, прежде чем продолжить. По пунктам:

Дайан заявляет: «Нет причин для создания подкласса от Application. Это ничем не отличается от создания синглтона ...» Это первое утверждение неверно. Для этого есть две основные причины. 1) Класс Application обеспечивает лучшую пожизненную гарантию для разработчика приложения; у него гарантированно будет время жизни приложения. Синглтон НЕ ЯВНО привязан к времени жизни приложения (хотя это эффективно). Это может быть не проблема для вашего среднего разработчика приложений, но я бы сказал, что это именно тот тип контракта, который должен предлагать Android API, и он также обеспечивает гораздо большую гибкость для системы Android, сводя к минимуму время жизни связанных данные. 2) Класс Application предоставляет разработчику приложения единственного держателя экземпляра для состояния, который сильно отличается от держателя одиночного экземпляра состояния. Список различий см. По ссылке объяснения Singleton выше.

Дайан продолжает: «... скорее всего, в будущем вы пожалеете о чем-то, о чем вы обнаружите, что ваш объект Application станет большим запутанным беспорядком из того, что должно быть независимой логикой приложения». Это, конечно, не неправильно, но это не причина выбора подкласса Singleton вместо подкласса Application. Ни один из аргументов Дайан не объясняет, почему использование синглтона лучше, чем подкласс приложения, все, что она пытается установить, - это то, что использование синглтона не хуже подкласса приложения, что, как я считаю, неверно.

Она продолжает: «И это более естественно ведет к тому, как вы должны управлять этими вещами - инициализировать их по запросу». Это игнорирует тот факт, что нет причин, по которым вы не можете инициализировать по запросу, также используя подкласс Application. Опять нет разницы.

Дайан заключает: «В самой структуре есть тонны и тонны синглтонов для всех небольших общих данных, которые она поддерживает для приложения, таких как кеши загруженных ресурсов, пулы объектов и т. Д. Она отлично работает». Я не утверждаю, что использование синглтонов не может работать нормально или не является законной альтернативой. Я утверждаю, что синглтоны не обеспечивают такой прочный контракт с системой Android, как использование подкласса Application, и, кроме того, использование синглтонов обычно указывает на негибкий дизайн, который нелегко изменить, и в дальнейшем приводит к множеству проблем. ИМХО, прочный контракт, который Android API предлагает разработчикам приложений, является одним из самых привлекательных и приятных аспектов программирования с Android, и помог привести к раннему принятию разработчиками, которые привели платформу Android к успеху, который она имеет сегодня. Предложение использовать синглтоны неявно отходит от сильного контракта API и, на мой взгляд, ослабляет платформу Android.

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

Я оставляю вам следующий список недостатков синглтонов, украденных по предыдущей ссылке на StackExchange:

  • Невозможность использования абстрактных или интерфейсных классов;
  • Невозможность подкласса;
  • Высокая степень сцепления в приложении (сложно изменить);
  • Сложно тестировать (не может подделывать / имитировать в модульных тестах);
  • Трудно распараллелить в случае изменяемого состояния (требуется обширная блокировка);

и добавить свой:

  • Неясный и неуправляемый пожизненный контракт, не подходящий для разработки под Android (или для большинства других);
person sooniln    schedule 02.04.2009
comment
Спасибо, Soonil - такие ответы - причина, по которой я так люблю Stack Overflow. ОТЛИЧНАЯ РАБОТА! - person JohnnyLambada; 25.09.2009
comment
Для тех, кто задается вопросом, как указать этот класс в теге приложения в вашем манифесте, на момент написания этой статьи есть два других ответа на этот вопрос, которые описывают, как это сделать (используйте android: name), один от ebuprofen и один от Майка. Коричневый. - person Tyler Collier; 11.11.2010
comment
@Soonil: Я только что добавил ответ, который на самом деле должен был быть комментарием к вашему ответу. Однако было слишком много времени, чтобы размещать это здесь как комментарий. - person Vit Khudenko; 10.01.2011
comment
Вскоре ваш ответ правильный, но не могли бы вы заметить, что мы должны добавить ‹application android: name = .MyApp ... /› в файл манифеста Android? - person anticafe; 20.02.2011
comment
как вызвать getApplicationContext () или getApplication () внутри типичного onClickListener? `loginButton.setOnClickListener (new View.OnClickListener () {public void onClick (View v) {}});` заранее спасибо! - person Cole; 16.04.2011
comment
Здравствуйте, я создал класс, который расширяет приложение и включает его в манифест, но я получаю это исключение: ERROR / AndroidRuntime (10404): Причина: java.lang.ClassCastException: android.app.Application - person Dayerman; 11.05.2011
comment
У меня также есть исключение ClassCase. Есть предположения ? - person Chinthaka; 16.10.2011
comment
@Soonil Спасибо! Было много таких проблем, это решило их. - person Neeta; 20.12.2011
comment
Я также получаю исключение CastException, когда пытаюсь преобразовать объект контекста, полученный из getApplicationContext (), в MyApp. Если я не использую его, а просто вставляю в обычную переменную Context, он работает нормально, но если я попытаюсь преобразовать его, это просто не сработает. Кто-нибудь знает решение? - person Dror; 06.01.2012
comment
как я могу получить эту глобальную переменную в неактивном классе? - person βhargavḯ; 19.05.2012
comment
также обратите внимание, что class должен быть public - person Cfr; 05.12.2012
comment
Объект приложения гарантированно создается до всех ваших действий и сохраняется до тех пор, пока все ваши действия не будут уничтожены. Однако вы не можете использовать его для глобального состояния, потому что Android может уничтожить все ваши действия И объект приложения, когда ваше приложение находится в фоновом режиме. - person Jared Kells; 19.04.2013
comment
Если вы получаете телефонный звонок ИЛИ переключаете приложения, что может означать просто запуск намерения браузера, ОС может при желании уничтожить все ваши действия, уничтожить объект вашего приложения и завершить процесс хостинга. Когда вы завершите телефонный звонок, начнется новый процесс, будет создан новый объект приложения и будет создано новое действие. Единственное состояние, которое вы получите обратно, будет в пакете, переданном в onCreate. Все ваши статические переменные будут нулевыми, а ваш объект Application будет совершенно новым экземпляром. - person Jared Kells; 19.04.2013
comment
Похоже, здесь описано plus.google.com/u/0/117230458394250799679/posts / DsfpW51Vvow одним из основных разработчиков Android, использование приложения для хранения данных вместо синглтона не рекомендуется. - person Dayerman; 26.07.2013
comment
@Somatik От: developer.android.com/reference/android/app/Application.html Обычно нет необходимости создавать подклассы Application. В большинстве случаев статические синглтоны могут предоставлять ту же функциональность более модульным способом. ... - Это действительно очень странная вещь для Google писать. Как объяснил Сансилн, веских причин отдавать предпочтение синглетонам нет. Это можно было бы понять, если бы они почувствовали необходимость указать, что синглтоны являются альтернативой, но не заявить, что они лучше. Создается впечатление, что кто-то одержим одиночками. - person RenniePet; 27.09.2013
comment
Запутанный беспорядок - я думаю, что Дайан говорит, что размещение всех глобальных объектов в Приложении нарушает принцип локальности: во многих случаях глобал может быть определен (как синглтон) в связанном модуле, где вы можете лучше увидеть, как он используется. Если вы используете синглтон в файле класса, тогда код будет более модульным (как на developer.android.com). - person Lucy; 09.11.2013
comment
@Lucy Если разработчики стремятся сделать компоненты глобально доступными, будь то синглтоны или шаблон приложения, обычно это связано с тем, что компонент должен быть глобально (или близок к глобальному) доступным. Например, постоянный сетевой компонент или информация для входа в систему, как в исходном вопросе, должны быть доступны из всех частей приложения. Конечно, сам компонент должен быть модульным, но вопрос здесь в том, как показать компонент другим частям приложения, и я по-прежнему убежден, что шаблон приложения - лучшее решение, чем одиночные. - person sooniln; 16.01.2014
comment
@ Tenfour04 Большинство из этих пунктов представляют собой более общую критику синглтонов, которая имеет мало общего с подклассами приложений или разработкой Android. Я указываю на эту общую критику и добавляю свою собственную критику; это Приложение является аффордансом Android, тогда как синглтон - возможностью Java. Для разработчика Android нет строгой гарантии, что синглтон привязан к вашему приложению (хотя это, конечно, практика), и эта гарантия есть для Application. - person sooniln; 05.02.2014
comment
@sooniln: у статических элементов данных такое же время жизни, как у Application и ваших ContentProvider экземпляров: время жизни процесса. В конце концов, Application - это просто статический член данных класса фреймворка. - person CommonsWare; 02.04.2014
comment
Позвольте мне повторить еще раз, вам не следует использовать приложение для глобальных объектов. Он бесполезен, не дает никаких преимуществ по сравнению с одиночными версиями и может быть активно вредным, например, снижать производительность запуска вашего процесса. Во время создания приложения вы не знаете, для чего создается ваш процесс. Лениво инициализируя синглтоны по мере необходимости, вам нужно выполнять только необходимую работу. Например, если ваш процесс запускается для обработки трансляции о каком-то фоновом событии, нет причин инициализировать любое глобальное состояние, необходимое вашему пользовательскому интерфейсу. - person hackbod; 08.04.2014
comment
Вдобавок ко всему, если ваше приложение использует несколько процессов, объект Application означает, что вам необходимо выполнить всю эту глобальную инициализацию (потребление времени и памяти) во всех из них. Ой. И есть определенные ситуации, когда ваш объект Application не будет создан, в частности, во время восстановления, что может вас сбить с толку. - person hackbod; 08.04.2014
comment
Кроме того, давайте проясним здесь - все ваши аргументы против синглтонов совершенно справедливы, когда мы говорим о ситуациях, когда вы на самом деле выбираете между синглтоном и другим подходом, который не является глобальным; синглтоны являются глобальными, со всеми применимыми оговорками в отношении глобальных переменных. Однако Приложение также является одноэлементным. Вы не избежите этих проблем, переключившись на подклассы Application. Приложение точно такое же, как синглтон (но хуже), оно просто позволяет вам обмануть себя, что вы делаете что-то более чистое. Но это не так. - person hackbod; 08.04.2014
comment
Приложение вводится в контекст, что позволяет вам передать любую реализацию приложения, которую вы хотите. Внедрение зависимостей (DI). Это важное различие, поскольку оно позволяет нам тестировать наши действия изолированно и в дальнейшем внедрять реализации модулей из нашего пользовательского приложения. Синглтоны объединяют классы, требуя, чтобы вы всегда отправляли один класс с другим. Это не модульный принцип, поскольку вы не можете легко предоставить другую реализацию синглтона. DI был бы наиболее веской причиной избегать одиночных запросов и отдавать предпочтение подклассу приложений. - person Joony; 14.04.2014
comment
Круто ! Помимо того, что это полезно, просто интересно, сколько очков вы заработали бы, принимая это как ответ :) :)! - person Raulp; 17.04.2014
comment
@hackbod Спасибо за ответ, жаль, что не видел его раньше! Я согласен с перечисленными вами проблемами с подклассами приложений, но я бы сказал, что это A) недостатки дизайна в классе Application (не пытаясь возложить вину, мы все знаем, как сложно сделать идеальный первоначальный выбор, а затем они запекаются in и невозможно изменить ...) и B) вы, кажется, приравниваете ленивую инициализацию - только - к синглетонам, когда вполне возможно использовать ее с подклассами Application. В моем первоначальном ответе следовало подчеркнуть это больше, но в то время это был очень общий ответ. - person sooniln; 14.05.2014
comment
@hackbod Я всегда использовал подклассы Application в качестве центрального справочника для различных служб приложений (связанных с пользовательским интерфейсом, с сетью и т. д.). При этом каждая служба является автономной и не контролируется подклассом Application, а фактически создается лениво. К сожалению, мой пример в ответе не включал этого, поскольку я пытался упростить его до самого необходимого. Я изменил пример, чтобы лучше отразить это. Например, в то время как приложение имеет ссылку на MyNetworkManager, MyNetworkManager может выполнять создание экземпляра и работать лениво. - person sooniln; 14.05.2014
comment
@hackbod Я согласен с тем, что ленивая инициализация - это очень хорошо, но для этого нет необходимости полагаться на синглтоны Java, вы также можете лениво инициализировать через подкласс Application, в дополнение к получению всех преимуществ отказа от использования синглтонов. Вы заплатите небольшую дополнительную стоимость строительства объекта, но я считаю, что если он спроектирован правильно, это должно быть незначительным и стоит преимуществ от отказа от одиночных конструкций. Я изменил свой первоначальный ответ, чтобы еще больше подчеркнуть это. - person sooniln; 14.05.2014
comment
Я всегда использовал Application for globals, но благодаря вашим таким противоречивым ответам картина теперь ясна. Чтобы избежать более длинного (App) context.getApplicationContext (), у меня был статический метод App.from (context), который уже предполагает, что в моем классе App нет ничего особенного - это может быть любой синглтон, совершенно не связанный с платформой Android. Поэтому я перестал использовать класс Application - это как сбросить все ваши константы в класс под названием Constants, и да, если вы не будете осторожны, запуск приложения будет раздутым. Спасибо еще раз! Очень полезный пост. - person myself; 30.11.2014
comment
PS Будьте осторожны, скоро - person myself; 30.11.2014
comment
так здорово! У меня тоже есть эти проблемы, я это понимаю по этим отзывам. - person zys; 13.01.2016
comment
Я должен использовать (Globals) getApplication() в каждом методе моей деятельности, который требует глобальных данных? Невозможно использовать статические методы? (И используйте Globals.getMyVariable()). - person JCarlosR; 13.08.2016
comment
Я не могу найти никаких официальных документов, которые однозначно говорят о том, может ли приложение быть уничтожено для последующего автоматического восстановления (а-ля действия и фрагменты). Следующая страница кажется единственной, на которой обсуждается уничтожение приложения. Я хочу, чтобы команда Android раз и навсегда прояснила, кто прав, а кто виноват, явно указав, могут ли приложения, уничтоженные в фоновом режиме, позже быть воссозданы в фоновом режиме. Какая позиция является мифом, а какая нет? developer.android.com/guide/components/activities/ - person Joe Lapp; 21.05.2019

Создайте этот подкласс

public class MyApp extends Application {
  String foo;
}

В AndroidManifest.xml добавьте android: name

Пример

<application android:name=".MyApp" 
       android:icon="@drawable/icon" 
       android:label="@string/app_name">
person Guillaume    schedule 26.07.2010
comment
Спасибо за это. Мне было интересно, как объявить это в манифесте - person Someone Somewhere; 05.05.2011
comment
Чтобы он работал у меня, мне пришлось удалить. внутри .MyApp - person Someone Somewhere; 05.05.2011
comment
просто объявите его после основного действия, иначе он не сможет установить / развернуть - person sami; 29.08.2011
comment
просто хочу сказать, это входит в тег MAIN приложения, который уже существует ... это не второй :) пришлось усвоить трудный путь. - person bwoogie; 14.10.2011
comment
bwoogie хотел бы дать вам +100, спас меня после нескольких часов путаницы - person Zach; 10.07.2014

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

Рассмотрим случай - ваше приложение уходит в фоновый режим, потому что вам кто-то звонит (приложение «Телефон» сейчас на переднем плане). В этом случае && при некоторых других условиях (проверьте ссылку выше, что они могут быть) ОС может убить процесс вашего приложения, включая экземпляр подкласса Application. В результате состояние потеряно. Когда вы позже вернетесь в приложение, ОС восстановит свой стек активности и экземпляр Application подкласса, однако поле myState будет null.

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

person Vit Khudenko    schedule 09.01.2011
comment
+1 за сохранение с SharedPreferences; вот как я это видел. Мне действительно кажется странным злоупотреблять системой предпочтений для сохраненного состояния, но она работает настолько хорошо, что проблема становится просто вопросом терминологии. - person Cheezmeister; 22.02.2011
comment
@Cheezmeister: +1. Я также использовал SharedPreferences для сохранения и доступа к состоянию. Это глобально и сохраняется. Единственным недостатком может быть дополнительная доля секунды, необходимая для чтения / записи. - person OceanBlue; 15.04.2011
comment
не могли бы вы опубликовать код (или предоставить ссылку на объяснение) относительно того, как SharedPreferences используется для решения проблемы, описанной Архимедом - person Someone Somewhere; 05.05.2011
comment
Настройки, база данных, сериализация файлов и т. Д. Каждое действие может поддерживать состояние, если оно использует onSaveInstanceState, но это не поможет, если пользователь откажется от действия и удалит его из стека истории, принудительно закрывает или выключает свое устройство. . - person Darren Hinderer; 23.06.2011
comment
Такое поведение очень раздражает - было бы не так уж плохо, если бы в вашем приложении был вызван метод onTerminate (), чтобы вы могли элегантно справиться с ситуацией. - person Dean Wild; 28.06.2012
comment
Какие-нибудь примеры из этого, пожалуйста? - person M.ES; 10.12.2012
comment
На мой взгляд, это правильный ответ. Ошибочно полагаться на один и тот же экземпляр приложения, существующий во всех действиях. По моему опыту, Android довольно часто полностью разрушает и воссоздает весь ваш процесс, пока вы находитесь в фоновом режиме. Быть на заднем плане может просто означать запуск намерения камеры, намерение браузера или получение телефонного звонка. - person Jared Kells; 19.04.2013
comment
Вам не нужно злоупотреблять общими предпочтениями, если сохраняемые данные используются только в этом экземпляре процесса. Когда Android убивает Activity, он вызывает onSaveInstanceState (Bundle). Данные в объекте Bundle хранятся в системной памяти, и это одна область памяти, которая не исчезнет, ​​пока ваш процесс находится в памяти. Данные могут быть позже использованы в onCreate (Bundle) или onRestoreInstanceState (Bundle). Если у вас нет данных, которые необходимо сохранить вне процесса, вам следует использовать пакет. Несмотря на незначительность, связка работает быстрее, поскольку находится в основной памяти, а не на диске. - person Ryhan; 04.08.2013
comment
Превосходно. Это именно то, что происходит с моим приложением: после возвращения после долгого времени в фоновом режиме оно пытается восстановить Activity, но данные в моих объектах Application нулевые, что вызывает NPE! - person braincell; 07.01.2014
comment
Я не могу найти никаких официальных документов, в которых говорится, что приложение может быть воссоздано позже после уничтожения. Единственная страница, на которой я могу найти обсуждение этого вопроса, - это эта, и на ней упоминаются только условия, при которых это приведет к уничтожению приложения. Тем не менее, он также не говорит, что позже не будет пытаться воссоздать приложение. Думаю, мы запутались, потому что документации недостаточно. developer.android.com/guide/components/activities/ - person Joe Lapp; 21.05.2019

Просто примечание ..

Добавить:

android:name=".Globals"

или как вы назвали свой подкласс в существующем <application> теге. Я все пытался добавить в манифест еще один тег <application> и получал исключение.

person Gimbl    schedule 13.04.2011
comment
Привет, Гимбл. У меня такая же проблема. У меня также был свой собственный тег ‹application›, и когда я пытаюсь добавить еще один тег ‹application›, у меня была та же проблема, что и у вас (сообщение об исключении). Но я сделал то, что вы упомянули, и это не сработало. Я добавляю android: name = .GlobalClass в свой тег ‹application›, но он не работает. Можете ли вы полностью объяснить, как вы это решили? - person Sonhja; 23.09.2011
comment
Хорошее ‹manifest› ‹приложение android: name = .GlobalData› ‹/application› ‹/manifest›. Плохое ‹manifest› ‹application› ‹/application› ‹приложение android: name = .GlobalData› ‹/application› ‹/manifest› - person Gimbl; 26.09.2011

Как насчет обеспечения сбора собственной памяти с такими глобальными структурами?

У Activity есть onPause/onDestroy() метод, вызываемый при уничтожении, но у класса Application нет эквивалентов. Какой механизм рекомендуется для обеспечения того, чтобы глобальные структуры (особенно те, которые содержат ссылки на собственную память) должным образом собирались мусором, когда приложение либо уничтожается, либо стек задач помещается в фоновый режим?

person user608578    schedule 25.02.2011
comment
Очевидное решение - реализовать Closeable интерфейс для ваших объектов, отвечающих за собственные ресурсы, и убедитесь, что они управляются оператором try-with-resources или чем-то еще. В худшем случае вы всегда можете использовать финализатор объекта. - person sooniln; 14.05.2014

Я также не смог найти, как указать тег приложения, но после долгих поисков в Google это стало очевидным из документации файла манифеста: используйте android: name в дополнение к значку и метке по умолчанию в разделе приложения.

android: name Полное имя подкласса Application, реализованного для приложения. Когда процесс приложения запускается, этот класс создается перед любым из компонентов приложения.

Подкласс не является обязательным; большинству приложений он не понадобится. При отсутствии подкласса Android использует экземпляр базового класса Application.

person Mike Brown    schedule 14.01.2010

Просто вам нужно определить имя приложения, как показано ниже, которое будет работать:

<application
  android:name="ApplicationName" android:icon="@drawable/icon">
</application>
person Anand    schedule 07.01.2011

Как уже говорилось выше, ОС может убить ПРИЛОЖЕНИЕ без какого-либо уведомления (нет события onDestroy), поэтому нет возможности сохранить эти глобальные переменные.

SharedPreferences может быть решением, ЗА ИСКЛЮЧЕНИЕМ у вас есть КОМПЛЕКСНЫЕ СТРУКТУРИРОВАННЫЕ переменные (в моем случае у меня был целочисленный массив для хранения идентификаторов, которые пользователь уже обработал). Проблема с SharedPreferences заключается в том, что эти структуры трудно сохранять и извлекать каждый раз, когда требуются значения.

В моем случае у меня была фоновая СЕРВИС, поэтому я мог переместить туда эти переменные, и поскольку у службы есть событие onDestroy, я мог легко сохранить эти значения.

person Adorjan Princz    schedule 02.11.2012
comment
onDestroy () не может быть вызван даже для службы. - person Learn OpenGL ES; 25.07.2013
comment
Да, такое могло случиться, но только в критических ситуациях. - person Adorjan Princz; 26.07.2013

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

Так что найдите правильный путь, а лучшего пути нет.

person user716653    schedule 20.04.2011

У вас может быть статическое поле для хранения такого состояния. Или поместите его в пакет ресурсов и восстановите оттуда на onCreate (Bundle savedInstanceState). Просто убедитесь, что вы полностью понимаете управляемый жизненный цикл приложения Android (например, почему login () вызывается при изменении ориентации клавиатуры).

person yanchenko    schedule 02.04.2009

НЕ НУЖНО Используйте другой тег <application> в файле манифеста. Просто внесите одно изменение в существующий тег <application>, добавьте эту строку android:name=".ApplicationName", где ApplicationName будет именем вашего подкласса (используется для хранения глобальных данных), который вы собирается создать.

Итак, наконец, ваш тег ONE AND ONLY <application> в файле манифеста должен выглядеть так: -

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.NoActionBar"
        android:name=".ApplicationName"
        >
person kumar kundan    schedule 22.06.2015

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

person Raju yourPepe    schedule 16.07.2013

Сделать это можно двумя способами:

  1. Использование класса приложения
  2. Использование общих настроек

  3. Использование класса приложения

Пример:

class SessionManager extends Application{

  String sessionKey;

  setSessionKey(String key){
    this.sessionKey=key;
  }

  String getSessisonKey(){
    return this.sessionKey;
  }
}

Вы можете использовать приведенный выше класс для реализации входа в систему в MainActivity, как показано ниже. Код будет выглядеть примерно так:

@override 
public void onCreate (Bundle savedInstanceState){
  // you will this key when first time login is successful.
  SessionManager session= (SessionManager)getApplicationContext();
  String key=getSessisonKey.getKey();
  //Use this key to identify whether session is alive or not.
}

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

  1. Использование общих предпочтений.

    String MYPREF="com.your.application.session"
    
    SharedPreferences pref= context.getSharedPreferences(MyPREF,MODE_PRIVATE);
    
    //Insert key as below:
    
    Editot editor= pref.edit();
    
    editor.putString("key","value");
    
    editor.commit();
    
    //Get key as below.
    
    SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
    
    String key= getResources().getString("key");
    
person Krishna    schedule 19.12.2015

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

person user3044482    schedule 11.10.2014

Подход подклассов также использовался структурой BARACUS. С моей точки зрения создание подклассов Приложение предназначалось для работы с жизненными циклами Android; это то, что делает любой контейнер приложения. Вместо того, чтобы иметь глобальные переменные, я регистрирую bean-компоненты в этом контексте и позволяю им внедряться в любой класс, управляемый контекстом. Каждый внедренный экземпляр bean-компонента на самом деле является синглтоном.

Подробнее см. в этом примере

Зачем заниматься ручным трудом, если можно намного больше?

person gorefest    schedule 11.11.2014

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

public class MyApplication extends Application {
    private String str = "My String";

    synchronized public String getMyString {
        return str;
    }
}

А затем, чтобы получить доступ к этой переменной в своей деятельности, используйте это:

MyApplication application = (MyApplication) getApplication();
String myVar = application.getMyString();
person Amit Tiwari    schedule 28.11.2015