是否有一种方法来获得静态方法内的当前上下文实例?
我正在寻找这种方式,因为我讨厌保存'Context'实例每次它改变。
是否有一种方法来获得静态方法内的当前上下文实例?
我正在寻找这种方式,因为我讨厌保存'Context'实例每次它改变。
当前回答
我刚刚发布了一个基于jquery的Android框架,名为Vapor API,旨在简化应用开发。
中心$ facade类维护了一个WeakReference(链接到Ethan Nicholas关于此的出色Java博客文章)到当前Activity上下文,您可以通过调用:
$.act()
WeakReference在不阻止垃圾回收回收原始对象的情况下维护引用,因此不应该存在内存泄漏问题。
当然,缺点是您要承担$.act()可能返回null的风险。我还没有遇到过这种情况,所以这可能只是一个最小的风险,值得一提。
如果你不使用VaporActivity作为你的Activity类,你也可以手动设置上下文:
$.act(Activity);
此外,许多Vapor API框架固有地使用这种存储上下文,这可能意味着如果您决定使用该框架,您根本不需要自己存储它。请查看该网站以获取更多信息和示例。
我希望这对你有所帮助:)
其他回答
另一种获得上下文而不子类化Application对象和不使用隐藏类的方法是使用ContentProvider。一旦onCreate方法被调用,上下文应该是可用的。您可以在Kotlin中执行类似的操作
class ContextContentProvider : ContentProvider() {
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?) = 0
override fun getType(uri: Uri): String? = null
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
override fun onCreate(): Boolean {
applicationContext = context
return true
}
override fun query(
uri: Uri, projection: Array<String>?, selection: String?,
selectionArgs: Array<String>?, sortOrder: String?
): Cursor? = null
override fun update(
uri: Uri, values: ContentValues?, selection: String?,
selectionArgs: Array<String>?
) = 0
companion object {
private var applicationContext: Context? = null
@JvmStatic
fun applicationContext() = applicationContext
}
}
在任何需要上下文的地方,都可以调用ContextContentProvider.applicationContext()方法
如果你已经有了另一个内容提供程序,并且没有导出该内容提供程序,请确保在AndroidManifest.xml中使用不同的权限。
<application>
<provider
android:name=".ContextContentProvider"
android:authorities="${applicationId}.ContextContentProvider"
android:enabled="true"
android:exported="false" />
</application>
如果你不想修改清单文件,你可以手动将上下文存储在初始活动的静态变量中:
public class App {
private static Context context;
public static void setContext(Context cntxt) {
context = cntxt;
}
public static Context getContext() {
return context;
}
}
当你的activity(或多个activity)开始时,只需设置上下文:
// MainActivity
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set Context
App.setContext(getApplicationContext());
// Other stuff
}
注意:与所有其他答案一样,这是一个潜在的内存泄漏。
如果你出于某种原因想在任何类中都有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 with中初始化它
GlobalAppContextSingleton.getInstance().initialize(this);
在任何地方通过调用使用它
GlobalAppContextSingleton.getInstance().getApplicationContext()
但是,除了应用程序上下文之外,我不推荐使用这种方法。因为它会导致内存泄漏。
在Kotlin中,将Context/App Context放在同伴对象中仍然会产生警告,不要将Android Context类放在静态字段中;这是一个内存泄漏(也破坏了即时运行)
或者如果你使用这样的东西:
companion object {
lateinit var instance: MyApp
}
这只是愚弄lint不发现内存泄漏,App实例仍然可以产生内存泄漏,因为Application类及其后代是一个Context。
或者,你可以使用功能界面或功能属性来帮助你获得应用上下文。
简单地创建一个对象类:
object CoreHelper {
lateinit var contextGetter: () -> Context
}
或者你可以使用nullable type更安全:
object CoreHelper {
var contextGetter: (() -> Context)? = null
}
在你的App类中添加这一行:
class MyApp: Application() {
override fun onCreate() {
super.onCreate()
CoreHelper.contextGetter = {
this
}
}
}
在你的manifest中声明应用名。MyApp
<application
android:name=".MyApp"
当你想获取上下文时,只需调用:
CoreHelper.contextGetter()
// or if you use the nullable version
CoreHelper.contextGetter?.invoke()
希望能有所帮助。
如今,拥有上下文的正确方法是使用依赖注入。 例如,可以使用Hilt在任何需要的地方注入上下文。假设一个人需要某个数据库管理器中的上下文,那么这可以通过以下方式解决:
在Gradle中添加刀柄:
implementation "com.google.dagger:hilt-android:2.35"
kapt "com.google.dagger:hilt-android-compiler:2.35"
用@HiltAndroidApp注解定义Application类(例如,让它注入数据库管理器):
@HiltAndroidApp
class MyApplication : Application() {
@Inject
lateinit var dbManager: DBManager
override fun onCreate() {
super.onCreate()
dbManager.initDB()
}
}
定义数据库管理器(以@Singleton为例):
@Singleton
class DBManager @Inject constructor(
@ApplicationContext private val context: Context
) {
fun initDB() {
// context is avaiable
databaseInit(context)
}
}
就是这样。DBManager可以以正确的方式访问上下文,没有内存泄漏。