是否有一种方法来获得静态方法内的当前上下文实例?

我正在寻找这种方式,因为我讨厌保存'Context'实例每次它改变。


当前回答

在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()

希望能有所帮助。

其他回答

如果你出于某种原因想在任何类中都有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()

但是,除了应用程序上下文之外,我不推荐使用这种方法。因为它会导致内存泄漏。

大多数想要一个方便的方法来获取应用上下文的应用程序都会创建自己的类来扩展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中,反射经常被轻视,我个人认为不应该在产品中使用。

要检索应用程序上下文,我们必须调用一个隐藏类(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);
} 

编码快乐!

这样做:

在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()来静态地获取应用程序上下文。

另一种获得上下文而不子类化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>

下面是一种从UI线程中的任何地方获取应用程序(它是一个上下文)的未记录的方法。它依赖于隐藏的静态方法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,例如,当你在UI线程之外调用这个方法时,或者应用程序没有绑定到线程上。

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