Android - 如何从小部件访问房间数据库
Posted
技术标签:
【中文标题】Android - 如何从小部件访问房间数据库【英文标题】:Android - How to access Room database from widget 【发布时间】:2019-01-29 03:10:36 【问题描述】:我想访问我的小部件类中的 Room DB,以根据存储的数据更新小部件。
这里的问题是 ViewModelProvider 需要一个片段或活动才能使用..
ViewModelProviders.of(fragment).get(YourViewModel.class);
应用小部件类中没有,怎么办?
【问题讨论】:
【参考方案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 )
【讨论】:
以上是关于Android - 如何从小部件访问房间数据库的主要内容,如果未能解决你的问题,请参考以下文章