Adrian Le Roy Devezin
Adrian Le Roy Devezin

Reputation: 843

Widget updated inside updateAppWidget not displaying any list data

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

Answers (1)

Elletlar
Elletlar

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

Related Questions