Использование контекста приложения во всем мире?

В приложении для Android есть что-то неправильное в следующем подходе:

public class MyApp extends android.app.Application { private static MyApp instance; public MyApp() { instance = this; } public static Context getContext() { return instance; } } 

И передавать его повсюду (например, SQLiteOpenHelper), где требуется контекст (а не утечка, конечно)?

Есть пара потенциальных проблем с этим подходом, хотя во многих случаях (например, в вашем примере) это будет работать хорошо.

В частности, вы должны быть осторожны при работе со всем, что связано с GUI который требует Context . Например, если вы передадите контекст приложения в LayoutInflater вы получите Исключение. Вообще говоря, ваш подход превосходный: рекомендуется использовать Context Activity Управлении и Application Context при передаче контекста за пределы действия Activity чтобы избежать утечек памяти .

Кроме того, в качестве альтернативы вашему шаблону вы можете использовать ярлык вызова getApplicationContext() для объекта Context (например, Activity) для получения контекста приложения.

По моему опыту, этот подход не должен быть необходимым. Если вам нужен контекст для всего, что вы обычно можете получить через вызов View.getContext () и используя полученный Контекст, вы можете вызвать Context.getApplicationContext (), чтобы получить контекст приложения. Если вы пытаетесь получить контекст приложения из этого действия, вы всегда можете вызвать Activity.getApplication (), который должен быть передан как Контекст, необходимый для вызова SQLiteOpenHelper ()

В целом, похоже, не проблема с вашим подходом к этой ситуации, но при работе с Context просто убедитесь, что вы не пропускаете память в любом месте, как описано в официальном блоге Google Android Developers

Некоторые люди спрашивали: как синглтон может вернуть нулевой указатель? Я отвечаю на этот вопрос. (Я не могу ответить в комментарии, потому что мне нужно отправить код.)

Он может возвращать значение null между двумя событиями: (1) класс загружается и (2) создается объект этого класса. Вот пример:

 class X { static X xinstance; static Y yinstance = Y.yinstance; X() {xinstance=this;} } class Y { static X xinstance = X.xinstance; static Y yinstance; Y() {yinstance=this;} } public class A { public static void main(String[] p) { X x = new X(); Y y = new Y(); System.out.println("x:"+X.xinstance+" y:"+Y.yinstance); System.out.println("x:"+Y.xinstance+" y:"+X.yinstance); } } 

Давайте запустим код:

 $ javac A.java $ java A x:X@a63599 y:Y@9036e x:null y:null 

Вторая строка показывает, что Y.xinstance и X.yinstance равны нулю ; Они равны нулю, поскольку переменные X.xinstance ans Y.yinstance были прочитаны, когда они были нулевыми.

Может ли это быть исправлено? Да,

 class X { static Y y = Y.getInstance(); static X theinstance; static X getInstance() {if(theinstance==null) {theinstance = new X();} return theinstance;} } class Y { static X x = X.getInstance(); static Y theinstance; static Y getInstance() {if(theinstance==null) {theinstance = new Y();} return theinstance;} } public class A { public static void main(String[] p) { System.out.println("x:"+X.getInstance()+" y:"+Y.getInstance()); System.out.println("x:"+Y.x+" y:"+Xy); } } 

И этот код не показывает аномалии:

 $ javac A.java $ java A x:X@1c059f6 y:Y@152506e x:X@1c059f6 y:Y@152506e 

НО это не вариант для объекта Android Application : программист не контролирует время его создания.

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

Вы пытаетесь создать оболочку для получения контекста приложения, и есть вероятность, что он может вернуть указатель « null ».

По моему пониманию, я думаю, что его лучший подход к вызову – любой из 2 Context.getApplicationContext() или Activity.getApplication() .

Класс применения:

 import android.app.Application; import android.content.Context; public class MyApplication extends Application { private static Context mContext; public void onCreate() { super.onCreate(); mContext = getApplicationContext(); } public static Context getAppContext() { return mContext; } } 

Объявите приложение в AndroidManifest:

 <application android:name=".MyApplication" ... /> 

Применение:

 MyApplication.getAppContext() 

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

И поскольку вы упомянули SQLiteOpenHelper : In onCreate () вы также можете открыть базу данных.

Лично я думаю, что в документации было неправильно говорить, что обычно нет необходимости в подклассе Application . Я думаю, что обратное верно: вы всегда должны подклассировать приложение.

Я бы использовал Application Context, чтобы получить системную службу в конструкторе. Это облегчает тестирование и преимущества от состава

 public class MyActivity extends Activity { private final NotificationManager notificationManager; public MyActivity() { this(MyApp.getContext().getSystemService(NOTIFICATION_SERVICE)); } public MyActivity(NotificationManager notificationManager) { this.notificationManager = notificationManager; } // onCreate etc } 

Тогда тестовый класс будет использовать перегруженный конструктор.

Android будет использовать конструктор по умолчанию.

Мне это нравится, но я бы предложил вместо него синглтон:

 package com.mobidrone; import android.app.Application; import android.content.Context; public class ApplicationContext extends Application { private static ApplicationContext instance = null; private ApplicationContext() { instance = this; } public static Context getInstance() { if (null == instance) { instance = new ApplicationContext(); } return instance; } } 

Я использую тот же подход, я предлагаю написать синглтон немного лучше:

 public static MyApp getInstance() { if (instance == null) { synchronized (MyApp.class) { if (instance == null) { instance = new MyApp (); } } } return instance; } 

Но я не использую везде, я использую getContext() и getApplicationContext() где я могу это сделать!