Reputation: 843
I have a widget that is supposed to display a list of information. however after researching numerous tutorials and the documentation I cannot figure out why it is not displaying the list. it will always show the empty view. The WidgetService.java class is never even called.
My code can be found on github here:
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);
}
}
WidgetService.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;
}
}
Upvotes: 1
Views: 244
Reputation: 3234
The problem is here in this method:
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);
}
On the line:
widget.setRemoteAdapter(appWidgetId, R.id.widget_configuration_list_view, serviceIntent);
It is the wrong list view, a mistake easily made with the R.id global name space. It should be:
widget.setRemoteAdapter(R.id.widget_recipe_list_view, serviceIntent);
That is the ListView in the remote view in the widget.
Also take note that I changed "setRemoteAdapter" to use a different version that is not deprecated.
Once this change has been made, onGetViewFactory is called inside the WidgetService. However, this results in a crash in the DB:
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)
But I'll leave that one to you because I think you're ready to make more progress now that the RemoteViewsFactory is being called. Cheers!
Upvotes: 2