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

烘焙应用Widget获取ROOM数据库实例时崩溃问题求助

解决Widget中ROOM数据库实例获取的NullPointerException问题

嘿,我一眼就看出你这个问题的症结所在了——当主应用被关闭后,Widget所在的进程重启时,你的BakingApp静态上下文还没初始化,导致调用getApplicationContext()时踩了空指针!

问题根源拆解

当主应用进程被销毁,Widget单独运行(或系统重启Widget进程)时,你的BakingApp类的onCreate()方法还没来得及执行,mContext变量还是null。这时候你在onDataSetChanged()里调用BakingApp.getContext()拿到的就是null,把这个null传到AppDatabase.getInstance()里,自然就触发了NullPointerException。

靠谱的解决方案(推荐方案1)

方案1:改用Widget传入的Context获取数据库实例

你的BakingAppRemoteViewsFactory已经在构造方法里拿到了合法的mContext,直接用这个上下文就好,完全没必要依赖静态的Application上下文。

  1. 修改RecipeRepository的构造方法:
    把原来接收Application改成接收Context,兼容性更强:

    public RecipeRepository(Context context){
        AppDatabase appDatabase = AppDatabase.getInstance(context);
        recipesDao = appDatabase.recipesDao();
    }
    
  2. 调整RemoteViewsFactory的onDataSetChanged方法:
    用持有的mContext代替BakingApp.getContext()初始化仓库:

    @Override
    public void onDataSetChanged() {
        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
        recipeID = sharedPreferences.getInt(RECIPE_ID, 0);
        // 这里换成mContext,再也不用怕空指针了
        recipeRepository = new RecipeRepository(mContext);
        recipe = recipeRepository.getCurrentRecipe(recipeID);
        ingredients = recipe.getRecipeIngredients();
    }
    
  3. 加固AppDatabase.getInstance()的逻辑:
    添加上下文非空检查,并且确保使用ApplicationContext避免内存泄漏:

    public static AppDatabase getInstance(Context context){
        if (context == null) {
            throw new IllegalArgumentException("Context must not be null!");
        }
        if (sInstance == null){
            synchronized (LOCK){
                // 先拿到全局的ApplicationContext,避免持有Widget/Activity的上下文导致泄漏
                Context appContext = context.getApplicationContext();
                sInstance = Room.databaseBuilder(appContext, AppDatabase.class, DATABASE_NAME)
                    .fallbackToDestructiveMigration()
                    .build();
            }
        }
        Log.d(LOG_TAG, "Getting the db instance");
        return sInstance;
    }
    

方案2:修复静态Application上下文的可靠性(备选)

如果你非要用静态上下文,那得给BakingApp的getContext()加个安全检查,避免返回null:

public class BakingApp extends Application {
    private static BakingApp mContext;

    @Override
    public void onCreate() {
        super.onCreate();
        mContext = this;
    }

    public static BakingApp getContext(){
        if (mContext == null) {
            throw new IllegalStateException("Application context hasn't been initialized yet!");
        }
        return mContext;
    }
}

不过这个方案有隐患——Widget进程启动时,Application的onCreate()可能还没执行,所以还是方案1更稳妥。

额外提醒

Widget是运行在独立进程(或主应用进程重启后的环境)的,绝对不能依赖主应用里的静态变量状态,一定要用Widget自身提供的合法上下文来获取系统资源、数据库这些东西。另外用Room的时候,一定要用ApplicationContext创建实例,不然很容易踩内存泄漏的坑!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:17:21