在Android中获取“上下文”的静态方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2002288/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 04:09:44  来源:igfitidea点击:

Static way to get 'Context' in Android?

androidandroid-context

提问by Andrea Baccega

Is there a way to get the current Contextinstance inside a static method?

有没有办法Context在静态方法中获取当前实例?

I'm looking for that way because I hate saving the 'Context' instance each time it changes.

我正在寻找那种方式,因为我讨厌每次更改时保存“上下文”实例。

回答by Rohit Ghatol

Do this:

做这个:

In the Android Manifest file, declare the following.

在 Android 清单文件中,声明以下内容。

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

</application>

Then write the class:

然后编写类:

public class MyApplication extends Application {

    private static Context context;

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

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

Now everywhere call MyApplication.getAppContext()to get your application context statically.

现在到处调用MyApplication.getAppContext()以静态获取您的应用程序上下文。

回答by Jared Rummler

The majority of apps that want a convenient method to get the application context create their own class which extends android.app.Application.

大多数需要一种方便的方法来获取应用程序上下文的应用程序都会创建自己的类,该类扩展android.app.Application.

GUIDE

指导

You can accomplish this by first creating a class in your project like the following:

您可以通过首先在您的项目中创建一个类来完成此操作,如下所示:

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

Then, in your AndroidManifest you should specify the name of your class in the AndroidManifest.xml's tag:

然后,在您的 AndroidManifest 中,您应该在 AndroidManifest.xml 的标签中指定您的类的名称:

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

You can then retrieve the application context in any static method using the following:

然后,您可以使用以下任何静态方法检索应用程序上下文:

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


WARNING

警告

Before adding something like the above to your project you should consider what the documentation says:

在将上述内容添加到您的项目之前,您应该考虑文档中的内容:

There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a Context which internally uses Context.getApplicationContext() when first constructing the singleton.

通常不需要子类化应用程序。在大多数情况下,静态单例可以以更加模块化的方式提供相同的功能。如果您的单例需要全局上下文(例如注册广播接收器),则可以为检索它的函数提供一个 Context,该 Context 在首次构造单例时在内部使用 Context.getApplicationContext()。



REFLECTION

反射

There is also another way to get the application context using reflection. Reflection is often looked down upon in Android and I personally think this should not be used in production.

还有另一种使用反射获取应用程序上下文的方法。反射在 Android 中经常被人看不起,我个人认为这不应该在生产中使用。

To retrieve the application context we must invoke a method on a hidden class (ActivityThread) which has been available since API 1:

要检索应用程序上下文,我们必须调用从 API 1 开始就可用的隐藏类 ( ActivityThread)上的方法:

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

There is one more hidden class (AppGlobals) which provides a way to get the application context in a static way. It gets the context using ActivityThreadso there really is no difference between the following method and the one posted above:

还有一个隐藏类 ( AppGlobals),它提供了一种以静态方式获取应用程序上下文的方法。它使用上下文获取上下文,ActivityThread因此以下方法与上面发布的方法之间确实没有区别:

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


Happy coding!

快乐编码!

回答by Alessio

Assuming we're talking about getting the Application Context, I implemented it as suggested by @Rohit Ghatol extending Application. What happened then, it's that there's no guarantee that the context retrieved in such a way will always be non-null. At the time you need it, it's usually because you want to initialize an helper, or get a resource, that you cannot delay in time; handling the null case will not help you. So I understood I was basically fighting against the Android architecture, as stated in the docs

假设我们正在谈论获取应用程序上下文,我按照@Rohit Ghatol 扩展应用程序的建议实现了它。然后发生了什么,无法保证以这种方式检索的上下文总是非空的。在你需要它的时候,通常是因为你想初始化一个助手,或者获取一个资源,你不能及时拖延;处理 null 情况对您没有帮助。所以我明白我基本上是在与 Android 架构作斗争,如文档中所述

Note: There is normally no need to subclass Application. In most situations, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), include Context.getApplicationContext() as a Context argument when invoking your singleton's getInstance() method.

注意:通常不需要子类化应用程序。在大多数情况下,静态单例可以以更加模块化的方式提供相同的功能。如果您的单例需要全局上下文(例如注册广播接收器),请在调用单例的 getInstance() 方法时将 Context.getApplicationContext() 作为 Context 参数包含在内。

and explained by Dianne Hackborn

Dianne Hackborn解释

The only reason Application exists as something you can derive from is because during the pre-1.0 development one of our application developers was continually bugging me about needing to have a top-level application object they can derive from so they could have a more "normal" to them application model, and I eventually gave in. I will forever regret giving in on that one. :)

应用程序作为您可以从中派生的东西而存在的唯一原因是,在 1.0 之前的开发过程中,我们的一位应用程序开发人员不断地问我需要有一个可以从中派生的顶级应用程序对象,以便他们可以拥有更“正常的” “给他们应用模型,我最终让步了。我将永远后悔放弃那个。:)

She is also suggesting the solution to this problem:

她还提出了解决这个问题的建议:

If what you want is some global state that can be shared across different parts of your app, use a singleton. [...] And this leads more naturally to how you should be managing these things -- initializing them on demand.

如果您想要的是一些可以在应用程序的不同部分之间共享的全局状态,请使用单例。[...] 这更自然地导致您应该如何管理这些东西——按需初始化它们。

so what I did was getting rid of extending Application, and pass the context directly to the singleton helper's getInstance(), while saving a reference to the application context in the private constructor:

所以我所做的是摆脱扩展应用程序,并将上下文直接传递给单例助手的 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;
    }
}

the caller will then pass a local context to the helper:

然后调用者会将本地上下文传递给助手:

Helper.getInstance(myCtx).doSomething();

So, to answer this question properly: there are ways to access the Application Context statically, but they all should be discouraged, and you should prefer passing a local context to the singleton's getInstance().

因此,要正确回答这个问题:有一些方法可以静态访问应用程序上下文,但都不鼓励使用它们,您应该更喜欢将本地上下文传递给单例的 getInstance()。



For anyone interested, you can read a more detailed version at fwd blog

对于任何有兴趣的人,您可以在fwd 博客上阅读更详细的版本

回答by Erich Douglass

No, I don't think there is. Unfortunately, you're stuck calling getApplicationContext()from Activityor one of the other subclasses of Context. Also, thisquestion is somewhat related.

不,我认为没有。不幸的是,您被困在getApplicationContext()Activity或 的其他子类之一调用Context. 另外,这个问题有点相关。

回答by kennytm

Here is an undocumentedway to get an Application(which is a Context) from anywhere in the UI thread. It relies on the hidden static method ActivityThread.currentApplication(). It should work at least on Android 4.x.

这是从 UI 线程中的任何位置获取应用程序(即上下文)的一种未公开的方法。它依赖于隐藏的静态方法。它应该至少适用于 Android 4.x。ActivityThread.currentApplication()

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
}

Note that it is possible for this method to return null, e.g. when you call the method outside of the UI thread, or the application is not bound to the thread.

请注意,此方法有可能返回 null,例如,当您在 UI 线程之外调用该方法时,或者应用程序未绑定到该线程时。

It is still better to use @RohitGhatol's solution if you can change the Application code.

如果您可以更改应用程序代码,最好使用@RohitGhatol的解决方案。

回答by gulchrider

It depends on what you are using the context for. I can think of at least one disadvantage to that method:

这取决于您使用上下文的目的。我可以想到该方法的至少一个缺点:

If you are trying to create an AlertDialogwith AlertDialog.Builder, the Applicationcontext won't work. I believe you need the context for the current Activity...

如果您尝试创建AlertDialogwith AlertDialog.Builder,则Application上下文将不起作用。我相信你需要当前的上下文Activity......

回答by phnmnn

Kotlin way:

科特林方式

Manifest:

显现:

<application android:name="MyApplication">

</application>

MyApplication.kt

我的应用程序.kt

class MyApplication: Application() {

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

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

You can then access the property via MyApplication.instance

然后,您可以通过访问该属性 MyApplication.instance

回答by user605331

If you're open to using RoboGuice, you can have the context injected into any class you want. Here's a small sample of how to do it with RoboGuice 2.0 (beta 4 at time of this writing)

如果您愿意使用RoboGuice,您可以将上下文注入到您想要的任何类中。这是一个关于如何使用 RoboGuice 2.0(撰写本文时为 beta 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) {
        }
    }
}

回答by ungalcrys

I've used this at some point:

我在某些时候使用过这个:

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

This is a valid context I used at getting system services and worked.

这是我用于获取系统服务并工作的有效上下文。

But, I used it only in framework/base modifications and did not try it in Android applications.

但是,我只在框架/基础修改中使用它,并没有在 Android 应用程序中尝试它。

A warningthat you must know: When registering for broadcast receivers with this context, it will not work and you will get:

一个警告,你必须知道:当广播接收机同此背景下注册,它不会工作,你会得到:

java.lang.SecurityException: Given caller package android is not running in process ProcessRecord

java.lang.SecurityException:给定的调用程序包 android 未在进程 ProcessRecord 中运行

回答by Khemraj

Kotlin

科特林

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

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

and get Context like

并获得 Context 之类的

MyApp.mInstance

or

或者

MyApp.getContext()