android - 在 updateAppWidget 内更新的小部件不显示任何列表数据
问题描述
我有一个应该显示信息列表的小部件。但是,在研究了大量教程和文档后,我无法弄清楚为什么它没有显示列表。它总是显示空视图。WidgetService.java 类甚至从未被调用过。
我的代码可以在 github 上找到:
RecipeWidgetProvider.java
public class RecipeWidgetProvider extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
SharedPreferences preferences = context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
long recipeId = preferences.getLong(WidgetConfigurationActivity.PREF_PREFIX_KEY+appWidgetId, 0);
Intent serviceIntent = new Intent(context, WidgetService.class);
serviceIntent.putExtra(WidgetService.EXTRA_RECIPE_ID, recipeId);
serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));
Intent intent = new Intent(context, RecipeListActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews widget = new RemoteViews(context.getPackageName(), R.layout.widget_recipes);
widget.setRemoteAdapter(appWidgetId, R.id.widget_configuration_list_view, serviceIntent);
widget.setEmptyView(R.id.widget_recipe_list_view, R.id.empty_view);
widget.setOnClickPendingIntent(R.id.widget_container, pendingIntent);
//appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_recipe_list_view);
appWidgetManager.updateAppWidget(appWidgetId, widget);
}
}
小部件服务.java
public class WidgetService extends RemoteViewsService {
public static String EXTRA_RECIPE_ID = "recipeId";
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
int recipeId = intent.getIntExtra(EXTRA_RECIPE_ID, -1);
return new WidgetViewFactory(getApplicationContext(), recipeId);
}
}
WidgetViewFactory.java
public class WidgetViewFactory implements RemoteViewsService.RemoteViewsFactory {
private Context context;
private long recipeId;
private ArrayList<IngredientEntity> ingredients = new ArrayList<>();
public WidgetViewFactory(Context context, long recipeId) {
this.context = context;
this.recipeId = recipeId;
RecipeLocalSource source = RecipeLocalSource.getInstance(context);
RecipeEntity recipe = source.getRecipe(recipeId);
if (recipe != null) {
ingredients.addAll(recipe.getIngredients());
}
}
@Override
public void onCreate() {
Log.e("","");
}
@Override
public void onDataSetChanged() {
RecipeLocalSource source = RecipeLocalSource.getInstance(context);
RecipeEntity recipe = source.getRecipe(recipeId);
if (recipe != null) {
ingredients.addAll(recipe.getIngredients());
}
}
@Override
public void onDestroy() {
Log.e("","");
}
@Override
public int getCount() {
Log.d("","");
return ingredients.size();
}
@Override
public RemoteViews getViewAt(int position) {
final IngredientEntity ingredient = ingredients.get(position);
RemoteViews row = new RemoteViews(context.getPackageName(),
R.layout.item_widget_ingredient);
row.setTextViewText(R.id.item_widget_ingredient_name, ingredient.getIngredient());
row.setTextViewText(R.id.item_widget_ingredient_quantity_measure, String.format("%s %s", ingredient.getQuantity(), ingredient.getMeasure()));
return row;
}
@Override
public RemoteViews getLoadingView() {
return null;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public boolean hasStableIds() {
return true;
}
}
解决方案
问题出在这种方法中:
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
SharedPreferences preferences = context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
long recipeId = preferences.getLong(WidgetConfigurationActivity.PREF_PREFIX_KEY+appWidgetId, 0);
Intent serviceIntent = new Intent(context, WidgetService.class);
serviceIntent.putExtra(WidgetService.EXTRA_RECIPE_ID, recipeId);
serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));
Intent intent = new Intent(context, RecipeListActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews widget = new RemoteViews(context.getPackageName(), R.layout.widget_recipes);
widget.setRemoteAdapter(appWidgetId, R.id.widget_configuration_list_view, serviceIntent);
widget.setEmptyView(R.id.widget_recipe_list_view, R.id.empty_view);
widget.setOnClickPendingIntent(R.id.widget_container, pendingIntent);
//appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_recipe_list_view);
appWidgetManager.updateAppWidget(appWidgetId, widget);
}
在线上:
widget.setRemoteAdapter(appWidgetId, R.id.widget_configuration_list_view, serviceIntent);
这是错误的列表视图,使用 R.id 全局名称空间很容易犯错误。它应该是:
widget.setRemoteAdapter(R.id.widget_recipe_list_view, serviceIntent);
那就是小部件中远程视图中的 ListView。
另请注意,我更改了“setRemoteAdapter”以使用未弃用的不同版本。
进行此更改后,将在 WidgetService 中调用 onGetViewFactory。但是,这会导致数据库崩溃:
java.lang.RuntimeException: Unable to bind to service intellidev.co.bakingapp.widget.WidgetService@15361cf with Intent { dat=intent: cmp=intellidev.co.bakingapp/.widget.WidgetService (has extras) }: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
at android.app.ActivityThread.handleBindService(ActivityThread.java:3538)
at android.app.ActivityThread.-wrap2(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1758)
at android.os.Handler.dispatchMessage(Handler.java:108)
at android.os.Looper.loop(Looper.java:206)
at android.app.ActivityThread.main(ActivityThread.java:6749)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:845)
Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
at android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:204)
at android.arch.persistence.room.RoomDatabase.query(RoomDatabase.java:232)
at intellidev.co.bakingapp.data.daos.RecipeDao_Impl.getRecipe(RecipeDao_Impl.java:129)
at intellidev.co.bakingapp.data.sources.RecipeLocalSource.getRecipe(RecipeLocalSource.java:47)
at intellidev.co.bakingapp.widget.WidgetViewFactory.<init>(WidgetViewFactory.java:24)
at intellidev.co.bakingapp.widget.WidgetService.onGetViewFactory(WidgetService.java:12)
at android.widget.RemoteViewsService.onBind(RemoteViewsService.java:241)
at android.app.ActivityThread.handleBindService(ActivityThread.java:3524)
at android.app.ActivityThread.-wrap2(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1758)
at android.os.Handler.dispatchMessage(Handler.java:108)
at android.os.Looper.loop(Looper.java:206)
at android.app.ActivityThread.main(ActivityThread.java:6749)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:845)
但是我将把那个留给你,因为我认为你已经准备好在调用 RemoteViewsFactory 后取得更多进展。干杯!
推荐阅读
- python - 递归与迭代函数 Python
- java - 在这个将前缀转换为后缀的程序中,为什么在执行以下代码时会显示运行时错误“ArrayIndexOutOfBound”?
- c - 为什么这个变量等于一个数字和一个字符?
- node.js - 使用 Express 访问静态内容和 API
- mysql - 如何复制表(MySQL)并自动更新新表?
- java - 如何从本地java应用程序连接到kerberized hive
- angular - 杀死 Angular 服务人员并用另一个服务人员替换的最佳方法是什么?
- python - 将字符串中的最后两个字母大写
- docker - 带有 LocalDB 的 Visual Studio 2017 docker 容器
- jakarta-ee - 分离实体传递错误