【问题标题】:Android - How to access Room database from widgetAndroid - 如何从小部件访问房间数据库
【发布时间】:2019-01-29 03:10:36
【问题描述】:

我想访问我的小部件类中的 Room DB,以根据存储的数据更新小部件。

这里的问题是 ViewModelProvider 需要一个片段或活动才能使用..

ViewModelProviders.of(fragment).get(YourViewModel.class);

应用小部件类中没有,怎么办?

【问题讨论】:

    标签: android android-widget android-room android-architecture-components android-database


    【解决方案1】:

    如果您使用RemoteViewsService 来填充您的小部件UI,那么您可以通过在其onDataSetChanged() 方法中而不是在AppWidgetProvider 的onUpdate() 方法中包含DAO 查询来避免使用AsyncTask。如onDataSetChanged() documentation中所述,

    ...可以在此方法中安全地同步执行昂贵的任务。在此期间,旧数据将显示在小部件中。

    这里的另一个优点是您可以在应用的 ViewModel 观察者的 onChanged() 方法中包含对 AppWidgetManager.notifyAppWidgetViewDataChanged() 的调用;这将触发onDataSetChanged(),并且每次更改房间数据库时,小部件都会更新,而不仅仅是onUpdate() 的固定间隔。

    【讨论】:

    • 您能否详细说明应该在哪里调用notifyAppWidgetViewDataChanged()?如果应该在 ViewModel 类中调用它,如何检索对 widgetIds 的引用?
    • @AleksandarStefanović,我真的很抱歉,但我已经有一段时间没有做这个了,我不记得具体的细节了。也许其他人可以回答。我建议您将其作为一个新问题发布。
    【解决方案2】:

    我知道这已经有一段时间了,但我只是遇到了这个问题,并想在其他成员 Aaron-dunigan-atlee 的启发下添加一些有用的东西。

    基本上显示了数据库和 Dao 对象的去向……更重要的是,onDataSetChanged() 方法调用了 Room 查询。 该示例用于说明应用程序的笔记,并且正如上面评论的那样,任何地方都不需要 AsyncTasks。

    public class MyWidgetRemoteViewsService extends RemoteViewsService
    {
        @Override
        public RemoteViewsFactory onGetViewFactory(Intent intent)
        {
            return new MyRemoteViewsFactory(this.getApplicationContext(), intent);
        }
    
        class MyRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory
        {
            private NotesDao notesDao;
            private List<Note> allNotes;
    
            MyRemoteViewsFactory(Context context, Intent intent)
            {
                MyDb db;
                db = MyDatabase.getDatabase(context);
                notesDao = db.notesDao();
            }
    
            @Override
            public void onCreate() { }
    
            @Override
            public void onDataSetChanged()
            {
                allNotes = notesDao.getAllNotes();
            }
    
            @Override
                public int getCount()
                { ...
    

    莎莎

    【讨论】:

      【解决方案3】:

      所以在这里回答我自己..

      唯一可行的方法是使用上下文从抽象类中获取数据库实例,并直接在后台线程中运行 DAO 查询,无需 ViewModelProviders 类

          new AsyncTask<Context, Void, List<Data>>(){
              @Override
              protected List<Quote> doInBackground(Context... context) {
      
                  List<Data> List=null;
                      AppDatabase db = AppDatabase.getDatabase(context[0]);
                      List = db.DataModel().getData();
      
      
                  return List;
              }
      
              @Override
              protected void onPostExecute(List<Quote> List) {
                  super.onPostExecute(List);
      
                  if(List != null){
      
                      final Random random=new Random();
                      for (int appWidgetId : appWidgetIds) {
                          updateAppWidget(context, appWidgetManager, appWidgetId, quoteList.get(random.nextInt(List.size())));
                      }
      
                  }
      
              }
      
          }.execute(context);
      
      }
      

      【讨论】:

        【解决方案4】:

        你可以不通过 ViewModel 访问 Room。ViewModel 只是 MVVM 架构的一个组件,就像 MVC 或 MVP 一样。没有 ViewModel,你仍然可以访问 Room,你只需要一个上下文

        【讨论】:

          【解决方案5】:

          您可以编写一个 Repository 类,并使用它来异步访问您的 Room 数据库。

          示例:https://codelabs.developers.google.com/codelabs/android-room-with-a-view/#7

          【讨论】:

            【解决方案6】:

            确实,你可以这样做..你已经需要从后台线程进行这个 DAO 查询,所以将上下文传递给 AsyncTask 以执行查询是一个很好的解决方案,但尝试在构造函数中传递上下文AsyncTask 而不是在参数中传递它。

            【讨论】:

              【解决方案7】:

              您不需要 ViewModel 来访问 Room 中的数据。您可以从任何地方访问数据,唯一要注意的是当数据更改不起作用时收到通知的令人敬畏的功能。为此,只需向您的 Dao 对象添加一个方法,该方法返回一个简单的 List 而不是 LiveData>。就是这样。

              【讨论】:

                【解决方案8】:

                在 JaviMar 在 Kotlin 中的回答中添加了一些关于某些事物如何组合在一起的更多信息:

                class RoomWidgetService : RemoteViewsService() {
                    override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
                        return RoomRemoteViewsFactory(this.applicationContext, intent)
                    }
                }
                
                class RoomRemoteViewsFactory(private val context: Context, intent: Intent) : RemoteViewsService.RemoteViewsFactory {
                    private var todos: List<TodoItem> = listOf()
                    private lateinit var todoDao: TodoDao
                
                
                    override fun onCreate() {
                        val database = TodoRoomDatabase.getDatabase(context)
                        todoDao = database.todoDao()
                    }
                
                    override fun onDataSetChanged() {
                        todos = todoDao.getTodosSync()
                    }
                    // rest of class...
                }
                
                

                我通过观察某些东西来通知小部件更新。您可以在主要活动或应用程序中观察 ViewModel。不确定观察数据的最佳位置。

                        todoViewModel.todoItems.observe(this) {
                            val appWidgetManager = AppWidgetManager.getInstance(applicationContext)
                            val thisAppWidget = ComponentName(
                                applicationContext.packageName,
                                RoomWidget::class.java.name
                            )
                            val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
                            appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.list_view )
                        }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-06-26
                  • 1970-01-01
                  • 2020-09-10
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多