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

голоса
561

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

В основной активности 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.

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

Задан 02/04/2009 в 02:54
источник пользователем
На других языках...                            


17 ответов

голоса
930

Я написал этот ответ обратно в '09, когда Android является относительно новым, и там было много не очень хорошо установленные области в развитии Android. Я добавил длинное добавление в нижней части этого поста, обращаясь некоторой критика, и детализации философской несогласие я с использованием Одиночек, а не подклассы приложения. Читайте на свой страх и риск.

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

Более общая проблема вы столкнулись в том, как сохранить состояние через несколько видов деятельности и все части вашего приложения. Статическая переменная (например, одноэлементный) является распространенным 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;
  }
}

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

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.

Примечание 1: Кроме того, как anticafe прокомментировал для того, чтобы правильно связать свое переопределение приложения к приложению тег необходимо в файле манифеста. Опять же , увидеть Android документов для получения дополнительной информации. Пример:

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

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

ДОПОЛНЕНИЕ:

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

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

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

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

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

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

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

Я оставляю вас со следующим списком минусов Одиночки, украденные из ранее ссылки StackExchange:

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

и добавить мои собственные:

  • Неясный и неуправляемый пожизненный контракт неподходящий для Android (или большинство другого) развития;
Ответил 02/04/2009 в 05:34
источник пользователем

голоса
151

Создать этот подкласс

public class MyApp extends Application {
  String foo;
}

В AndroidManifest.xml добавить андроид: имя

пример

<application android:name=".MyApp" 
       android:icon="@drawable/icon" 
       android:label="@string/app_name">
Ответил 26/07/2010 в 21:31
источник пользователем

голоса
136

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

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

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

Ответил 09/01/2011 в 22:49
источник пользователем

голоса
25

Только примечание ..

Добавить:

android:name=".Globals"

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

Ответил 13/04/2011 в 22:29
источник пользователем

голоса
13

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

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

Ответил 25/02/2011 в 19:32
источник пользователем

голоса
13

Я не мог найти, как задать тег приложения либо, но после того, как много Googling, это стало очевидно из манифеста документов файла: использование Android: имя, в дополнении к значку по умолчанию и меток в строфе приложения.

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

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

Ответил 14/01/2010 в 06:26
источник пользователем

голоса
5

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

<application
  android:name="ApplicationName" android:icon="@drawable/icon">
</application>
Ответил 07/01/2011 в 06:57
источник пользователем

голоса
4

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

SharedPreferences может быть решением, КРОМЕ вас есть сложные структурированные переменные (в моем случае я имел целочисленный массив для хранения идентификаторов, которые пользователь уже обрабатываемых). Проблема с SharedPreferences является то, что трудно хранить и извлекать эти структуры каждый раз, необходимые значения.

В моем случае я имел фоновую службу, так что я мог бы перенести эти переменные там и потому, что служба имеет OnDestroy событие, я мог бы сохранить эти значения легко.

Ответил 02/11/2012 в 09:53
источник пользователем

голоса
4

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

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

Ответил 20/04/2011 в 08:32
источник пользователем

голоса
3

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

Ответил 02/04/2009 в 03:19
источник пользователем

голоса
2

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

так, наконец , ваш один и только <application> тег в файле манифеста должен выглядеть следующим образом : -

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.NoActionBar"
        android:name=".ApplicationName"
        >
Ответил 22/06/2015 в 11:20
источник пользователем

голоса
1

Вы можете сделать это, используя два подхода:

  1. Использование класса приложений
  2. Использование Shared Preferences

  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.
}

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

  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");
    
Ответил 19/12/2015 в 13:03
источник пользователем

голоса
0

Можно было бы создать класс , который расширяет 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();
Ответил 28/11/2015 в 13:05
источник пользователем

голоса
0

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

Смотрите этот пример для подробностей

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

Ответил 11/11/2014 в 13:01
источник пользователем

голоса
0

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

Ответил 11/10/2014 в 08:36
источник пользователем

голоса
0
class GlobaleVariableDemo extends Application {

    private String myGlobalState;

    public String getGlobalState(){
     return myGlobalState;
    }
    public void setGlobalState(String s){
     myGlobalState = s;
    }
}

class Demo extends Activity {

@Override
public void onCreate(Bundle b){
    ...
    GlobaleVariableDemo appState = ((GlobaleVariableDemo)getApplicationContext());
    String state = appState.getGlobalState();
    ...
    }
}
Ответил 17/07/2014 в 11:31
источник пользователем

голоса
0

Вы можете использовать Intents, SQLite или Shared Preferences. Когда дело доходит до хранения средств массовой информации, как документы, фотографии и видео, вы можете создать новые файлы вместо.

Ответил 16/07/2013 в 02:35
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more