And*_*ega 931 android android-context
有没有办法Context
在静态方法中获取当前实例?
我正在寻找那种方式,因为我讨厌每次更改时保存"Context"实例.
小智 1261
做这个:
在Android Manifest文件中,声明以下内容.
<application android:name="com.xyz.MyApplication">
</application>
Run Code Online (Sandbox Code Playgroud)
然后写下课程:
public class MyApplication extends Application {
private static Context context;
public void onCreate() {
super.onCreate();
MyApplication.context = getApplicationContext();
}
public static Context getAppContext() {
return MyApplication.context;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,到处调用MyApplication.getAppContext()
以静态获取应用程序上下文.
Jar*_*ler 80
大多数需要方便的方法来获取应用程序上下文的应用程序都会创建自己的扩展类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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,在AndroidManifest中,您应该在AndroidManifest.xml的标记中指定您的类的名称:
<application
...
android:name="com.example.App" >
...
</application>
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用以下方法在任何静态方法中检索应用程序上下文:
public static void someMethod() {
Context context = App.getContext();
}
Run Code Online (Sandbox Code Playgroud)
警告
在将类似上述内容添加到项目之前,您应该考虑文档说的内容:
通常不需要子类Application.在大多数情况下,静态单例可以以更模块化的方式提供相同的功能.如果你的单例需要一个全局上下文(例如注册广播接收器),那么检索它的函数可以给一个Context,它在第一次构造单例时在内部使用Context.getApplicationContext().
反射
还有另一种使用反射来获取应用程序上下文的方法.在Android中经常会忽略反思,我个人认为这不应该用于生产.
要检索应用程序上下文,我们必须在自API 1以来可用的隐藏类(ActivityThread)上调用一个方法:
public static Application getApplicationUsingReflection() throws Exception {
return (Application) Class.forName("android.app.ActivityThread")
.getMethod("currentApplication").invoke(null, (Object[]) null);
}
Run Code Online (Sandbox Code Playgroud)
还有一个隐藏类(AppGlobals)提供了一种以静态方式获取应用程序上下文的方法.它使用上下文,ActivityThread
所以下面的方法和上面发布的方法之间确实没有区别:
public static Application getApplicationUsingReflection() throws Exception {
return (Application) Class.forName("android.app.AppGlobals")
.getMethod("getInitialApplication").invoke(null, (Object[]) null);
}
Run Code Online (Sandbox Code Playgroud)
快乐的编码!
Ale*_*sio 56
假设我们正在讨论获取应用程序上下文,我按照@Rohit Ghatol扩展Application的建议实现了它.那时发生的事情是,不能保证以这种方式检索的上下文总是非空的.当你需要它时,通常是因为你想要初始化一个帮助器,或者获得一个你不能及时延迟的资源; 处理null case对你没有帮助.所以我理解我基本上是在与Android架构作斗争,正如文档中所述
注意:通常不需要子类Application.在大多数情况下,静态单例可以以更模块化的方式提供相同的功能.如果您的单例需要全局上下文(例如注册广播接收器),则在调用单例的getInstance()方法时将Context.getApplicationContext()包含为Context参数.
并由Dianne Hackborn解释
应用程序存在的唯一原因是因为在1.0之前的开发过程中,我们的一个应用程序开发人员不断地烦恼我需要拥有一个他们可以从中获得的顶级应用程序对象,这样他们就可以更加"正常" "对他们的应用模式,我最终屈服了.我会永远后悔屈服于那个.:)
她也建议解决这个问题:
如果你想要的是一个可以在应用程序的不同部分共享的全局状态,请使用单例.[...]这更自然地导致你应该如何管理这些东西 - 按需初始化它们.
所以我做的是摆脱扩展Application,并将上下文直接传递给singleton帮助器的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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后调用者将本地上下文传递给帮助者:
Helper.getInstance(myCtx).doSomething();
Run Code Online (Sandbox Code Playgroud)
因此,要正确回答这个问题:有一些方法可以静态访问应用程序上下文,但是所有这些都应该是不鼓励的,你应该更喜欢将本地上下文传递给单例的getInstance().
对于任何有兴趣的人,您可以在fwd博客上阅读更详细的版本
ken*_*ytm 37
这是一种从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
}
Run Code Online (Sandbox Code Playgroud)
请注意,此方法可能返回null,例如,当您在UI线程之外调用方法,或者应用程序未绑定到线程时.
如果您可以更改应用程序代码,那么使用@RohitGhatol的解决方案仍然会更好.
gul*_*der 32
这取决于您使用上下文的内容.我可以想到该方法至少有一个缺点:
如果您尝试创建AlertDialog
with AlertDialog.Builder
,则Application
上下文将不起作用.我相信你需要当前的背景Activity
......
use*_*331 11
如果您愿意使用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) {
}
}
}
Run Code Online (Sandbox Code Playgroud)
我在某个时候用过这个:
ActivityThread at = ActivityThread.systemMain();
Context context = at.getSystemContext();
Run Code Online (Sandbox Code Playgroud)
这是我用于获取系统服务和工作的有效上下文.
但是,我只在框架/基础修改中使用它,并没有在Android应用程序中尝试它.
一个警告,你必须知道:当广播接收机同此背景下注册,它不会工作,你会得到:
java.lang.SecurityException:给定调用程序包android没有在进程ProcessRecord中运行
科特林方式:
表现:
<application android:name="MyApplication">
</application>
Run Code Online (Sandbox Code Playgroud)
MyApplication.kt
class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
instance = this
}
companion object {
lateinit var instance: MyApplication
private set
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以通过MyApplication.instance访问该属性。
根据此来源,您可以通过扩展 ContextWrapper 来获取自己的 Context
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();
}
}
Run Code Online (Sandbox Code Playgroud)
Context 的代理实现,只需将其所有调用委托给另一个 Context。可以进行子类化以修改行为而不更改原始上下文。
如果您不想修改清单文件,您可以在初始活动中手动将上下文存储在静态变量中:
public class App {
private static Context context;
public static void setContext(Context cntxt) {
context = cntxt;
}
public static Context getContext() {
return context;
}
}
Run Code Online (Sandbox Code Playgroud)
并在您的活动(或活动)开始时设置上下文:
// MainActivity
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set Context
App.setContext(getApplicationContext());
// Other stuff
}
Run Code Online (Sandbox Code Playgroud)
注意:与所有其他答案一样,这是潜在的内存泄漏。
您可以使用以下内容:
MainActivity.this.getApplicationContext();
Run Code Online (Sandbox Code Playgroud)
MainActivity.java:
...
public class MainActivity ... {
static MainActivity ma;
...
public void onCreate(Bundle b) {
super...
ma=this;
...
Run Code Online (Sandbox Code Playgroud)
任何其他类别:
public ...
public ANY_METHOD... {
Context c = MainActivity.ma.getApplicationContext();
Run Code Online (Sandbox Code Playgroud)
如果出于某种原因您希望在任何类中使用应用程序上下文,而不仅仅是那些扩展应用程序/活动的类,也许对于某些工厂或帮助程序类。您可以将以下单例添加到您的应用程序中。
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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后在应用程序类的 onCreate 中初始化它
GlobalAppContextSingleton.getInstance().initialize(this);
Run Code Online (Sandbox Code Playgroud)
通过调用在任何地方使用它
GlobalAppContextSingleton.getInstance().getApplicationContext()
Run Code Online (Sandbox Code Playgroud)
但是,除了应用程序上下文之外,我不建议将此方法用于任何其他情况。因为它可能会导致内存泄漏。
open class MyApp : Application() {
override fun onCreate() {
super.onCreate()
mInstance = this
}
companion object {
lateinit var mInstance: MyApp
fun getContext(): Context? {
return mInstance.applicationContext
}
}
}
Run Code Online (Sandbox Code Playgroud)
并获得像
MyApp.mInstance
Run Code Online (Sandbox Code Playgroud)
要么
MyApp.getContext()
Run Code Online (Sandbox Code Playgroud)
在 Kotlin 中,将 Context/App Context 放在伴随对象中仍然会产生警告 Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)
或者如果你使用这样的东西:
companion object {
lateinit var instance: MyApp
}
Run Code Online (Sandbox Code Playgroud)
这只是愚弄 lint 没有发现内存泄漏,App 实例仍然会产生内存泄漏,因为 Application 类及其后代是一个 Context。
或者,您可以使用功能接口或功能属性来帮助您获取应用程序上下文。
只需创建一个对象类:
object CoreHelper {
lateinit var contextGetter: () -> Context
}
Run Code Online (Sandbox Code Playgroud)
或者您可以使用可空类型更安全地使用它:
object CoreHelper {
var contextGetter: (() -> Context)? = null
}
Run Code Online (Sandbox Code Playgroud)
并在您的 App 类中添加以下行:
class MyApp: Application() {
override fun onCreate() {
super.onCreate()
CoreHelper.contextGetter = {
this
}
}
}
Run Code Online (Sandbox Code Playgroud)
并在您的清单中将应用名称声明为 . MyApp
<application
android:name=".MyApp"
Run Code Online (Sandbox Code Playgroud)
当您想获取上下文时,只需调用:
CoreHelper.contextGetter()
// or if you use the nullable version
CoreHelper.contextGetter?.invoke()
Run Code Online (Sandbox Code Playgroud)
希望它会有所帮助。
归档时间: |
|
查看次数: |
650472 次 |
最近记录: |