Статический способ получить "контекст" в Android?


есть ли способ получить текущий Context экземпляр внутри статического метода?

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

20 829

20 ответов:

этого:

в файле манифеста Android, заявляю следующее.

<application android:name="com.xyz.MyApplication">

</application>

затем напишите класс:

public class MyApplication extends Application {

    private static Context context;

    public void onCreate() {
        super.onCreate();
        MyApplication.context = getApplicationContext();
    }

    public static Context getAppContext() {
        return MyApplication.context;
    }
}

Теперь везде звоните MyApplication.getAppContext() чтобы получить контекст приложения статически.

большинство приложений, которые хотят удобный метод, чтобы получить контекст приложения создать свой собственный класс, который расширяет android.app.Application.

руководство

вы можете сделать это, сначала создав класс в своем проекте следующим образом:

import android.app.Application;
import android.content.Context;

public class App extends Application {

    private static Application sApplication;

    public static Application getApplication() {
        return sApplication;
    }

    public static Context getContext() {
        return getApplication().getApplicationContext();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sApplication = this;
    }
}

затем в вашем AndroidManifest вы должны указать имя вашего класса в AndroidManifest.тег xml:

<application 
    ...
    android:name="com.example.App" >
    ...
</application>

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

public static void someMethod() {
    Context context = App.getContext();
}

предупреждение

прежде чем добавить что-то подобное выше в свой проект, вы должны рассмотреть, что говорится в документации:

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


отражение

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

чтобы получить контекст приложения мы необходимо вызвать метод для скрытого класса (ActivityThread), который был доступен с API 1:

public static Application getApplicationUsingReflection() throws Exception {
    return (Application) Class.forName("android.app.ActivityThread")
            .getMethod("currentApplication").invoke(null, (Object[]) null);
}

есть еще один скрытый класс ( AppGlobals), который обеспечивает способ получить контекст приложения в статическом виде. Он получает контекст с помощью ActivityThread таким образом, на самом деле нет никакой разницы между следующим методом и тем, который был опубликован выше:

public static Application getApplicationUsingReflection() throws Exception {
    return (Application) Class.forName("android.app.AppGlobals")
            .getMethod("getInitialApplication").invoke(null, (Object[]) null);
} 

удачи в кодировании!

Нет, я не думаю, что есть. К сожалению, вы застряли вызова getApplicationContext() с Activity или один из других подклассов Context. Кроме того,этой вопрос несколько связанных.

здесь недокументированные способ получить приложение (который является контекстом) из любой точки потока пользовательского интерфейса. Он опирается на скрытый статический метод ActivityThread.currentApplication(). Он должен работать по крайней мере на Android 4.x.

try {
    final Class<?> activityThreadClass =
            Class.forName("android.app.ActivityThread");
    final Method method = activityThreadClass.getMethod("currentApplication");
    return (Application) method.invoke(null, (Object[]) null);
} catch (final ClassNotFoundException e) {
    // handle exception
} catch (final NoSuchMethodException e) {
    // handle exception
} catch (final IllegalArgumentException e) {
    // handle exception
} catch (final IllegalAccessException e) {
    // handle exception
} catch (final InvocationTargetException e) {
    // handle exception
}

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

еще лучше использовать @RohitGhatol ' s решение, если вы можете изменить код приложения.

предполагая, что мы говорим о получении контекста приложения, я реализовал его в соответствии с предложением @Rohit Ghatol extending Application. То, что произошло тогда, заключается в том, что нет никакой гарантии, что контекст, полученный таким образом, всегда будет ненулевым. В то время, когда вам это нужно, обычно это происходит потому, что вы хотите инициализировать помощника или получить ресурс, который вы не можете задержать во времени; обработка нулевого случая не поможет вам. Так что я понял, что я в основном борюсь против Андроида архитектура, как указано в docs

Примечание: обычно нет необходимости в применении подкласс. В большинстве случаев статические синглеты могут обеспечивать ту же функциональность более модульным способом. Если ваш синглтон нуждается в глобальном контексте (например, для регистрации широковещательных приемников), включите контекст.getApplicationContext() в качестве аргумента контекста при вызове метода getInstance () вашего синглтона.

и пояснил Диана Hackborn

Она также предлагает решение этой проблемы проблема:

Если вы хотите, чтобы какое-то глобальное состояние было общим для разных частей вашего приложения, используйте синглтон. [...] И это более естественно приводит к тому, как вы должны управлять этими вещами-инициализировать их по требованию.

Итак, я избавился от расширения приложения и передал контекст непосредственно в getInstance () одноэлементного помощника, сохранив ссылку на контекст приложения в частном конструктор:

private static MyHelper instance;
private final Context mContext;    

private MyHelper(@NonNull Context context) {
    mContext = context.getApplicationContext();
}

public static MyHelper getInstance(@NonNull Context context) {
    synchronized(MyHelper.class) {
        if (instance == null) {
            instance = new MyHelper(context);
        }
        return instance;
    }
}

вызывающий объект затем передаст локальный контекст помощнику:

Helper.getInstance(myCtx).doSomething();

Итак, чтобы правильно ответить на этот вопрос: есть способы статического доступа к контексту приложения, но все они должны быть обескуражены, и вы должны предпочесть передачу локального контекста в getInstance () синглтона.


для всех, кто интересуется, можно прочитать более подробную версию блог fwd

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

если вы пытаетесь создать AlertDialog с AlertDialog.Builder на Application контекст не будет работать. Я считаю, что нужен контекст Activity...

Если вы открыты для использования RoboGuice, вы можете иметь контекст вводят в любой класс, который вы хотите. Вот небольшой пример как это сделать с RoboGuice 2.0 (бета 4 на момент написания этой статьи)

import android.content.Context;
import android.os.Build;
import roboguice.inject.ContextSingleton;

import javax.inject.Inject;

@ContextSingleton
public class DataManager {
    @Inject
    public DataManager(Context context) {
            Properties properties = new Properties();
            properties.load(context.getResources().getAssets().open("data.properties"));
        } catch (IOException e) {
        }
    }
}

я использовал это в какой-то момент:

ActivityThread at = ActivityThread.systemMain();
Context context = at.getSystemContext();

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

но, я использовал его только в рамках / базовых модификаций и не пробовал его в приложениях Android.

A предупреждение что вы должны знать: при регистрации для широковещательных приемников с этим контекстом, он не будет работать, и вы получите:

java.ленг.SecurityException: данный вызывающий пакет android является не работает в процессе ProcessRecord

Я думаю, что вам нужно тело для getAppContext() способ:

public static Context getAppContext()
   return MyApplication.context; 

вы можете использовать следующие:

MainActivity.this.getApplicationContext();

MainActivity.java:

...
public class MainActivity ... {
    static MainActivity ma;
...
    public void onCreate(Bundle b) {
         super...
         ma=this;
         ...

любой другой класс:

public ...
    public ANY_METHOD... {
         Context c = MainActivity.ma.getApplicationContext();

по данным этот источник вы можете получить свой собственный контекст, расширяя ContextWrapper

public class SomeClass extends ContextWrapper {

    public SomeClass(Context base) {
      super(base);
    }

    public void someMethod() {
        // notice how I can use "this" for Context
        // this works because this class has it's own Context just like an Activity or Service
        startActivity(this, SomeRealActivity.class);

        //would require context too
        File cacheDir = getCacheDir();
    }
}

JavaDoc для ContextWrapper

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

Я использую вариант Шаблона дизайна Синглтона, чтобы помочь мне в этом.

import android.app.Activity;
import android.content.Context;

public class ApplicationContextSingleton {
    private static Activity gContext;

    public static void setContext( Activity activity) {
        gContext = activity;
    }

    public static Activity getActivity() {
        return gContext;
    }

    public static Context getContext() {
        return gContext;
    }
}

Я тогда позвоню ApplicationContextSingleton.setContext( this ); в своем активности.onCreate () и ApplicationContextSingleton.setContext( null ); на onDestroy();

Я только что выпустил jQuery-вдохновленный фреймворк для Android под названием Vapor API это направлено на упрощение разработки приложений.

центральный $ фасад класс поддерживает WeakReference (ссылка на удивительный Java блог об этом Итан Николас) к текущему Activity контекст, который вы можете получить, позвонив:

$.act()

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

недостатком, конечно, является то, что вы рискуете, что $.act() может вернуть null. Я еще не сталкивался с этим сценарием, поэтому, возможно, это просто минимальный риск, о котором стоит упомянуть.

вы также можете установить контекст вручную, если вы не используете VaporActivity в своем Activity класс:

$.act(Activity);

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

Я надеюсь, что помогает :)

Если вам по какой-то причине нужен контекст приложения в любом классе, а не только те, которые расширяют приложение/Активность, возможно, для некоторых заводских или вспомогательных классов. Вы можете добавить в приложение следующий синглтон.

public class GlobalAppContextSingleton {
    private static GlobalAppContextSingleton mInstance;
    private Context context;

    public static GlobalAppContextSingleton getInstance() {
        if (mInstance == null) mInstance = getSync();
        return mInstance;
    }

    private static synchronized GlobalAppContextSingleton getSync() {
        if (mInstance == null) mInstance = 
                new GlobalAppContextSingleton();
        return mInstance;
    }

    public void initialize(Context context) {
        this.context = context;
    }

    public Context getApplicationContext() {
        return context;
    }
}

затем инициализируйте его в onCreate вашего класса приложения с помощью

GlobalAppContextSingleton.getInstance().initialize(this);

использовать его в любом месте вызова

GlobalAppContextSingleton.getInstance().getApplicationContext()

однако я не рекомендую этот подход ни к чему, кроме контекста приложения. Как это может привести к утечкам памяти.

поэтому я изменил принятый ответ, потому что он вызывает утечку памяти, это то, что я придумал...

AndroidManifest.xml

    <application android:name="com.xyz.MyApplication">
...

    </application>

Мое_приложение.java

public class MyBakingAppContext extends Application {
    private static Object mContext;

    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
    }

    public static Context getAppContext() {
        return (Context)mContext;
    }
}

что я на самом деле сделал, это присвоить контекст объекту и вернуть объект в качестве контекста(приведение его к контексту). Надеюсь, это поможет.

Если вы не хотите, чтобы изменить файл манифеста, вы можете вручную сохранить контекст в статической переменной в начальном деятельность:

public class App {
    private static Context context;

    public static void setContext(Context cntxt) {
        context = cntxt;
    }

    public static Context getContext() {
        return context;
    }
}

и просто установите контекст, когда ваша деятельность (или деятельность) начинается:

// MainActivity

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Set Context
    App.setContext(getApplicationContext());

    // Other stuff
}

Примечание: как и все остальные ответы, это потенциальная утечка памяти.

Котлин способом:

Манифест:

<application android:name="MyApplication">

</application>

Мое_приложение.КТ

class MyApplication: Application() {

    override fun onCreate() {
        super.onCreate()
        instance = this
    }

    companion object {
        lateinit var instance: MyApplication
            private set
    }
}

вы можете получить доступ к свойству через MyApplication.экземпляр

Я проверил все здесь описанные предложения и могу сказать:

Если я использую следующий код:

public class App extends Application {
    private static Context context;
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
    }

    public static Context getAppContext() {
        return context;
    }
}

Я получаю в студии 3 сообщение об ошибке:

Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run).

но если я использую следующий код:

public class App extends Application {
    private static List<Context> context = new ArrayList<>();

    @Override
    public void onCreate() {
        super.onCreate();
        context.add(0, getApplicationContext());
    }

    public static Context getAppContext() {
        return context.get(0);
    }       
} 

он работает нормально без каких либо ошибок.

ответ Рохита кажется правильным. Однако имейте в виду, что "мгновенный запуск" AndroidStudio зависит от отсутствия static Context атрибуты в коде, насколько я знаю.

В Котлин

open class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        mInstance = this
    }

    companion object {
        lateinit var mInstance: MyApp
        fun getContext(): Context? {
            return mInstance.applicationContext
        }
    }
}

и получить контекст, как

App.mInstance

или

MyApp.getContext()