有没有办法Context
在静态方法中获取当前实例?
我正在寻找这种方式,因为我讨厌每次更改“上下文”实例时都将其保存。
Context
,那么可能会有更好的方法来设计代码。
有没有办法Context
在静态方法中获取当前实例?
我正在寻找这种方式,因为我讨厌每次更改“上下文”实例时都将其保存。
Context
,那么可能会有更好的方法来设计代码。
Answers:
做这个:
在Android Manifest文件中,声明以下内容。
<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()
以静态获取您的应用程序上下文。
static context
变量声明为volatile
吗?
大多数希望使用便捷方法获取应用程序上下文的应用程序都会创建自己的扩展类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();
}
警告
在将上述内容添加到您的项目之前,应考虑文档说明:
通常不需要子类化Application。在大多数情况下,静态单例可以以更模块化的方式提供相同的功能。如果您的单身人士需要全局上下文(例如,注册广播接收者),则可以为该函数提供一个上下文,该上下文在首次构造单身人士时在内部使用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);
}
还有一个隐藏类(AppGlobals),它提供了一种以静态方式获取应用程序上下文的方法。它使用上下文,ActivityThread
因此以下方法与上面发布的方法之间确实没有区别:
public static Application getApplicationUsingReflection() throws Exception {
return (Application) Class.forName("android.app.AppGlobals")
.getMethod("getInitialApplication").invoke(null, (Object[]) null);
}
编码愉快!
假设我们正在讨论获取应用程序上下文,我按照@Rohit Ghatol扩展Application的建议实现了它。然后发生的事情是,不能保证以这种方式检索的上下文将始终为非null。在您需要它时,通常是因为您想初始化一个助手或获取资源,所以您不能延迟时间。处理null大小写将无济于事。因此,我知道我基本上是在与Android体系结构作斗争,如文档所述
注意:通常不需要子类化Application。在大多数情况下,静态单例可以以更模块化的方式提供相同的功能。如果您的单例需要全局上下文(例如,注册广播接收者),则在调用单例的getInstance()方法时将Context.getApplicationContext()作为Context参数。
并由Dianne Hackborn解释
应用程序存在的唯一原因是您可以从中衍生出东西,这是因为在1.0之前的开发过程中,我们的一位应用程序开发人员一直在困扰我,我需要一个可以从其派生的顶级应用程序对象,以便他们可以拥有更“正常”的对于他们的应用程序模型,我最终放弃了。我永远都会后悔放弃那个模型。:)
她还建议解决此问题的方法:
如果您想要的是可以在应用程序的不同部分之间共享的某些全局状态,请使用单例。[...]这更自然地导致您应该如何管理这些事情-按需初始化它们。
因此,我要做的是摆脱扩展Application的过程,并将上下文直接传递给单例助手的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博客上阅读更详细的版本。
getInstance(ctx)
。你有一个GC根instance
型的MyHelper
,其中有一个私有字段mContext
类型Context
,其中引用通过上下文收集应用程序上下文传递getInstance()
。 instance
不会再次设置或清除,因此GC永远不会捕获所引用的appcontext instance
。您不会泄漏任何活动,因此它是低成本的IMO。
this
在in中发布静态引用来简化此操作Application.onCreate()
,这将使接受的答案更好。
不,我认为没有。不幸的是,您被困getApplicationContext()
从中调用Activity
或其他子类之一Context
。另外,这个问题有些相关。
这是从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
}
请注意,例如,当您在UI线程之外调用该方法,或者应用程序未绑定到该线程时,此方法可能返回null。
如果可以更改应用程序代码,则最好使用@RohitGhatol的解决方案。
这取决于您使用上下文的目的。我可以想到该方法的至少一个缺点:
如果您尝试使用创建一个AlertDialog
with AlertDialog.Builder
,则Application
上下文将不起作用。我相信您需要当前的背景Activity
...
科特林方式:
表现:
<application android:name="MyApplication">
</application>
MyApplication.kt
class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
instance = this
}
companion object {
lateinit var instance: MyApplication
private set
}
}
然后,您可以通过访问属性 MyApplication.instance
如果您愿意使用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) {
}
}
}
您可以使用以下内容:
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();
如果您不想修改清单文件,则可以在初始活动中将上下文手动存储在静态变量中:
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
}
注意:像所有其他答案一样,这是潜在的内存泄漏。
根据此资源,您可以通过扩展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();
}
}
Context的代理实现,该实现只是将其所有调用委派给另一个Context。可以子类化以修改行为,而无需更改原始上下文。
如果您出于某种原因想要在任何类中使用Application上下文,而不仅仅是那些扩展应用程序/活动的类,则可能是在某些工厂或助手类中使用的。您可以将以下单例添加到您的应用中。
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()
除了应用程序上下文之外,我不建议将此方法用于任何其他情况。因为这可能导致内存泄漏。
我使用Singleton设计模式的一种变体来帮助我。
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 );
我的activity.onCreate()和ApplicationContextSingleton.setContext( null );
中的onDestroy() ;
我刚刚发布了一个受Android启发的jQuery框架,称为Vapor API,旨在简化应用程序开发。
中心的$
外观类维护着一个WeakReference
(到Ethan Nicholas的Java博客文章的链接)到当前Activity
上下文,您可以通过调用以下内容进行检索:
$.act()
A会WeakReference
在不阻止垃圾回收回收原始对象的情况下维护引用,因此您不会遇到内存泄漏的问题。
当然,缺点是您冒着$.act()
可能返回null 的风险。不过,我还没有遇到这种情况,所以值得一提的只是很小的风险。
如果您不用VaporActivity
作Activity
课程,也可以手动设置上下文:
$.act(Activity);
另外,许多Vapor API框架都固有地使用此存储的上下文,这意味着如果您决定使用该框架,则根本不需要自己存储它。请访问该站点以获取更多信息和样本。
希望对您有所帮助:)
在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
}
只是愚弄了皮棉而没有发现内存泄漏,因为Application类及其后代是Context,所以App实例仍然会产生内存泄漏。
另外,您可以使用功能接口或功能属性来帮助您获取应用上下文。
只需创建一个对象类:
object CoreHelper {
lateinit var contextGetter: () -> Context
}
或者您可以使用可为空的类型来更安全地使用它:
object CoreHelper {
var contextGetter: (() -> Context)? = null
}
并在您的App类中添加以下行:
class MyApp: Application() {
override fun onCreate() {
super.onCreate()
CoreHelper.contextGetter = {
this
}
}
}
并在清单中声明应用名称为 . MyApp
<application
android:name=".MyApp"
当您想获取上下文时,只需调用:
CoreHelper.contextGetter()
// or if you use the nullable version
CoreHelper.contextGetter?.invoke()
希望它会有所帮助。
试试这个
import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.os.Bundle; public class MainActivity extends AppCompatActivity { private static Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = getApplicationContext(); } public static void getContext(View view){ Toast.makeText(context, "Got my context!", Toast.LENGTH_LONG).show(); } }