You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法访问Application类的Android模块如何正确获取Context避免内存泄漏及循环依赖?

可行解决方案

方案1:依赖反转+手动初始化(推荐,可控性最高)

通过在当前模块定义接口,上层app模块实现接口并注入实例的方式规避循环依赖,同时确保获取的是安全的全局ApplicationContext:

  1. 在当前需要Context的模块中定义上下文提供者接口,不需要依赖任何app层代码:
public interface ContextProvider {
    Context getApplicationContext();
}
  1. 在模块内增加全局初始化入口,存储接口实现类实例,静态持有ApplicationContext不会产生内存泄漏:
public class YourModuleEntry {
    private static ContextProvider sProvider;

    // 仅需在app模块的Application#onCreate中调用一次
    public static void init(ContextProvider provider) {
        sProvider = provider;
    }

    // 模块内部获取全局Context的统一方法
    public static Context getAppContext() {
        if (sProvider == null) {
            throw new IllegalStateException("模块未初始化,请先在Application中调用YourModuleEntry.init()");
        }
        return sProvider.getApplicationContext();
    }
}
  1. app层不需要修改任何原有业务调用链,仅需在Application初始化时传入实现:
// app模块的Application类中
@Override
public void onCreate() {
    super.onCreate();
    YourModuleEntry.init(() -> getApplicationContext());
}
  1. 改造原方法:
private static synchronized String createDataPath(String path) {
    File fileDir = YourModuleEntry.getAppContext().getExternalFilesDir(path);
    return fileDir != null ? fileDir.getAbsolutePath() : null;
}

优点:无额外性能损耗,完全可控,无依赖冲突
缺点:需要上层加一行初始化代码


方案2:ContentProvider自动初始化(无侵入首选)

利用Android系统中ContentProvider的初始化机制,无需上层做任何配置即可自动获取ApplicationContext:

  1. 在当前模块中实现一个空的ContentProvider:
public class ModuleContextProvider extends ContentProvider {
    private static Context sAppContext;

    public static Context getAppContext() {
        return sAppContext;
    }

    @Override
    public boolean onCreate() {
        // 此处getContext返回的就是Application上下文,直接缓存即可
        sAppContext = getContext().getApplicationContext();
        return true;
    }

    // 其余增删改查方法无需实现,直接返回默认值即可
    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        return null;
    }
    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }
    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        return null;
    }
    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }
    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }
}
  1. 在当前模块的AndroidManifest.xml中注册该ContentProvider:
<provider
    android:name=".ModuleContextProvider"
    android:authorities="${applicationId}.yourmodule.contextprovider"
    android:exported="false" />

优点:完全无侵入,上层不需要做任何修改即可使用
缺点:会增加一个空的ContentProvider组件,对应用启动速度的影响几乎可以忽略,Jetpack AppStartup组件的底层就是基于该原理实现


方案3:依赖注入框架适配(适合已接入DI的项目)

如果项目已经接入Hilt、Dagger等依赖注入框架,直接通过DI提供ApplicationContext即可:

  1. 模块仅需依赖DI的注解包,不需要依赖app模块
  2. 在需要Context的位置直接注入全局上下文即可,以Hilt为例:
@Inject
@ApplicationContext
Context appContext;

注意事项

你之前遇到的静态Context内存泄漏问题,都是因为持有了Activity、Service等生命周期短于进程的组件实例,而静态持有ApplicationContext是完全安全的,它的生命周期和应用进程完全一致,不会产生任何内存泄漏,是Android官方推荐的全局Context获取方式。

内容的提问来源于stack exchange,提问作者Ludiras

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 03:15:02