Singleton
В языке Java для подобных случаев используется паттерн проектирования Singleton. Синглетон это класс у которого гарантировано есть только один экземпляр. В простом случае он выглядит так:- public class Singleton {
- private static Singleton instance;
- private Singleton (){
- }
- public static Singleton getInstance(){
- if (null == instance){
- instance = new Singleton();
- }
- return instance;
- }
- }
Это класс в котором определен статический экземпляр этого же класса. В методе getInstance (), если этот экземпляр еще не был инициализирован, то вызывается конструктор. Сам конструктор определен как private, а значит мы не можем вне этого класса создать экземпляр с помощью оператора new.
Попробуем сделать это в приложении android. Я создала приложение с двумя похожими деятельностями
Создадим класс MySingleton (в отдельном файле MySingleton.java):
- class MySingleton {
- private static MySingleton mInstance;
- private String MyVariable;
- public static MySingleton getInstance() {
- Log.w("MY_TAG", "MySingleton::getInstance()");
- if (mInstance == null) {
- mInstance = new MySingleton();
- }
- return mInstance;
- }
- private MySingleton() {
- Log.w("MY_TAG", "MySingleton::MySingleton()");
- MyVariable = "This is my Variable";
- }
- public String getMyVariable() {
- return MyVariable;
- }
- public void setMyVariable(String var) {
- MyVariable = var;
- }
- }
В классе определена переменная MyVariable, которая инициализируется в конструкторе и два метода для чтения и записи этой переменной getMyVariable() и setMyVariable().
В методы getInstance() и Singleton() я добавила отладочную печать Log.w(), чтобы в процессе работы приложения посмотреть как создается объект.
В обе деятельности добавим строчки
- public void onCreate(Bundle savedInstanceState) {
- ...
- Log.w("MY_TAG", "First Activity Start");
- EditText text = (EditText) findViewById(R.id.text);
- Singleton ms = MySingleton.getInstance();
- text.setText(ms.getMyVariable());
- }
Запустим: в обоих деятельностях в EditText пишется значение переменой.
Посмотрим отладочную печать, для этого в Eclipse надо включить панель LogCat. В меню выберем Window->ShowView->Other. В открывшемся окошке находим Android->LogCat и нажимаем ОК. Теперь внизу появилась вкладка LogCat, куда выводятся все сообщения с эмулятора или подключенного устройства. Для удобства можно включить фильтр по тегу (у меня это «MY_TAG»).
При работе нашего приложения мы увидим что-то такое:
* First Activity Start
* MySingleton::getInstance()
* MySingleton::MySingleton()
* Second Activity Start
* MySingleton::getInstance()
* First Activity Start
* MySingleton::getInstance()
Как мы видим, конструктор вызывался только при первом запуске FirstActivity, а дальше getInstance() только возвращал переменную. Свою основную задачу класс Singleton выполняет: у нас есть один экземпляр класса доступный из любого места приложения.
Но в таком подходе есть один недостаток. Мы создаем экземпляр класса Singleton в контексте текущей Activity и если эта Activity завершает свою работу, то и экземпляр класса будет уничтожен (причем не сразу, а когда сработает сборщик мусора Java). А значит при следующем вызове getInstance() объект будет создаваться заново (вновь вызовется конструктор). Если в классе Singleton мы храним какие-то статичные переменные или методы, то это можно просто проигнорировать.
Вполне очевидным решением данной проблемы является создание экземпляра класса Singleton (первый вызов getInstance()) в какой-то Activity, которая будет жить на протяжении всего времени работы приложения. Но система android не может гарантировать, что неактивная Activity не будет уничтожена в случае нехватки памяти.
Класс Application
Класс Application - это базовый класс приложения android. При запуске программы вначале создается экземпляр этого класса, а потом уже необходимые деятельности. Напишем собственную реализацию этого класса.Напишем в MyApp.java
- public class MyApp extends Application {
- @Override
- public void onCreate() {
- super.onCreate();
- Log.w("MY", "onCreate MyApp");
- MySingleton.initInstance();
- }
- }
В классе MySingleton разделим getInstance() на два метода:
- class MySingleton {
- ...
- public static void initInstance() {
- Log.d("MY", "MySingleton::InitInstance()");
- if (mInstance == null) {
- mInstance = new MySingleton();
- }
- }
- public static MySingleton getInstance() {
- Log.d("MY", "MySingleton::getInstance()");
- return mInstance;
- }
- ...
- }
Также надо прописать класс MyApp в AndroidManifest.xml
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:name=".MyApp">
- ...
- </application>
Запустим
Внешне ничего не изменилось, но теперь вне зависимости от того какие activities работают экземпляр класса MySingleton будет существовать.
Посмотрим логи:
onCreate MyApp
Singleton::InitInstance()
Singleton::Singleton()
First Activity Start
Singleton::getInstance()
Первым вызывается метод onCreate() класса MyApp в котором создается экземпляр класса MySingleton. Только после этого запускается FirstActivity.
В классе Application кроме метода void onCreate(), который вызывается при старте приложения есть также методы:
void onConfigurationChanged(Configuration newConfig) - Вызывается при изменении конфигурации устройства
void onLowMemory() - Вызывается когда система работает в условиях нехватки памяти, и просит работающие процессы попытаться сэкономить ресурсы.
void onTrimMemory(int level) - Вызывается, когда операционная система решает, что сейчас хорошее время для обрезания ненужной памяти из процесса.
Кстати, в классе Application можно хранить не только синглетоны, но и просто методы и переменные:
- public class MyApp extends Application {
- private String MyVariable;
- @Override
- public void onCreate() {
- ...
- }
- public String getMyVariable() {
- return MyVariable;
- }
- public void setMyVariable(String MyVariable) {
- this.MyVariable = MyVariable;
- }
- }
Обращаться к этим методам из любой activity можно так:
- public void onCreate(Bundle savedInstanceState) {
- ...
- MyApp app = ((MyApp) getApplicationContext());
- text.setText(app.getMyVariable());
- }
Спасибо. Чего дальше не пишите ? Реально очень все интересно. Лучше чем по английски объяснили. +100.
ОтветитьУдалитьСпасибо, рада, что оказалось полезным :)
УдалитьНе всегда руки доходят писать, скоро постараюсь новую статью написать )