При обновлении фона обновляется список виджетов Android. - PullRequest
0 голосов
/ 13 мая 2019

Я использую ListView для отображения информации в виджете Android.

Информация должна быть загружена из Интернета, который загружается с помощью Async Task, когда вызывается RemoveViewsFactory onDataSetChanged. После завершения асинхронной задачи снова вызывается метод onDataSetChanged и отображается только что полученная информация.

Хотя изначально все работает нормально, при обновлении, инициализированном Android («updatePeriodMillis»), ListView внутри виджета становится пустым. То есть ни записи больше не отображаются, ни заполнитель «Нет записей», который отображается, когда нет записей. Время обновления виджета по умолчанию установлено на один час.

Когда я принудительно обновляю вручную (с помощью кнопки на виджете), записи снова отображаются.

Согласно моим сообщениям в журнале отладки, метод onDataSetChanged вызывается до исчезновения записей, что вызывает необходимость обновления информации. awm.notifyAppWidgetViewDataChanged (awm - это AppWidgetManager) вызывается, но в конечном итоге public RemoteViews getViewAt(int position) не запускается (или этот метод возвращает null?), А также public int getCount() не вызывается.

[Изменить]
Похоже, что до завершения фонового опроса вызывается метод getCount() и возвращается 0. Однако после вызова метода initData из обратного вызова (т. Е. После появления новых данных) getCount() не вызывается снова. Я мог бы на самом деле заставить дополнительное принудительное обновление без фоновой загрузки тогда, но это было бы более хакерским обходным путем, чем действительно правильный способ сделать это.
[/ Edit]

Поскольку это довольно редкое событие (минимальное время обновления составляет 30 минут ...), мне очень трудно его отладить, и я надеюсь, что кто-то столкнулся с подобной проблемой.

Полный проект доступен здесь: Github

Вот выдержка из Кодекса:

public class VplanWidgetDataProvider implements RemoteViewsService.RemoteViewsFactory {
    // ...

    @Override
    public void onDataSetChanged() {
        plan = new Vplan(mContext, day);
        plan.loadFromCache();
        initData();
    }

    // ...

    private void initData() {
        Log.d("WIDGET", "INIT DATA: " + plan.getDay());
        nightmode = VplanWidget.useNightmode(mContext, widgetId);
        mCollection.clear();
        if (plan.isLoaded() && plan.upToDate()) {
            mCollection.clear();
            Log.d("WIDGET", "Data present");
            for (VplanEntry entry : plan.getEntries()) {
                mCollection.add(entry);
            }
            Log.d("WIDGET", "Entries: " + mCollection.size());
            Log.d("WIDGET", "Day: " + plan.getDayString());
            Log.d("WIDGET", "Date: " + plan.formatDate());
            Log.d("WIDGET", "NOTIFY");
            AppWidgetManager awm = AppWidgetManager.getInstance(mContext);
            awm.notifyAppWidgetViewDataChanged(awm.getAppWidgetIds(new ComponentName(mContext, VplanWidgetServiceToday.class)), R.id.widget_list_view);
            awm.notifyAppWidgetViewDataChanged(awm.getAppWidgetIds(new ComponentName(mContext, VplanWidgetServiceTomorrow.class)), R.id.widget_list_view);
        } else {
            Log.d("WIDGET", "Loading started");
            plan.load(new SuccessCallback() {
                @Override
                public void callback(boolean success) {
                    Log.d("WIDGET", "Loading finished: " + success);
                    if (success) {
                        onDataSetChanged();
                    }
                }
            });
        }

    @Override
    public RemoteViews getViewAt(int position) {
        if (mCollection.size() <= position) {
            return null;
        }

        VplanEntry entry = mCollection.get(position);
        nightmode = VplanWidget.useNightmode(mContext, widgetId);

        int layout = nightmode ? R.layout.vplan_widget_entry_dark : R.layout.vplan_widget_entry;

        RemoteViews view = new RemoteViews(mContext.getPackageName(), layout);
        view.setTextViewText(R.id.widget_plan_plan, entry.getPlan());
        view.setTextViewText(R.id.widget_plan_comment, entry.getComment());
        view.setTextViewText(R.id.widget_plan_substitution, entry.getSubstitution());
        view.setTextViewText(R.id.widget_plan_lesson, entry.getLesson());
        view.setTextViewText(R.id.widget_plan_cls, entry.getCls());

        if (entry.getComment().isEmpty()) {
            view.setViewVisibility(R.id.widget_plan_comment, View.GONE);
        } else {
            view.setViewVisibility(R.id.widget_plan_comment, View.VISIBLE);
        }
        if (entry.getSubstitution().isEmpty()) {
            view.setViewVisibility(R.id.widget_plan_substitution, View.GONE);
        } else {
            view.setViewVisibility(R.id.widget_plan_substitution, View.VISIBLE);
        }

        if (entry.getSubstitution().isEmpty() && entry.getComment().isEmpty()) {
            view.setViewVisibility(R.id.widget_arrow, View.GONE);
        } else {
            view.setViewVisibility(R.id.widget_arrow, View.VISIBLE);
        }

        return view;
    }

    @Override
    public int getViewTypeCount() {
        return 2;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }
}

И AppWidgetProvider:

public class VplanWidget extends AppWidgetProvider {
    // ...

    static void updateAppWidget(final Context context, final AppWidgetManager appWidgetManager,
                                final int appWidgetId, final boolean force) {

        Log.d("WIDGET", "UPDATE FOR WIDGET " + appWidgetId + " with Nightmode " + VplanWidget.useNightmode(context, appWidgetId));

        final CharSequence day = VplanWidgetConfigureActivity.loadDayPref(context, appWidgetId);
        CharSequence daystr;
        // Construct the RemoteViews object

        int layout = VplanWidget.useNightmode(context, appWidgetId) ? R.layout.vplan_widget_dark : R.layout.vplan_widget;

        final RemoteViews views = new RemoteViews(context.getPackageName(), layout);

        views.setOnClickPendingIntent(R.id.widget_fab, getPendingSelfIntent(context, SYNC_CLICKED, appWidgetId));

        if (day.equals("today")) {
            daystr = context.getString(R.string.plan_today);
        } else {
            daystr = context.getString(R.string.plan_tomorrow);
        }

        final Vplan plan = new Vplan(context, day.toString());
        views.setTextViewText(R.id.widget_title, daystr);

        MyTFGApi api = new MyTFGApi(context);

        if (!api.isLoggedIn()) {
            views.setTextViewText(R.id.widget_plan_empty, context.getString(R.string.widget_login_required));
            views.setViewVisibility(R.id.widget_plan_empty, View.VISIBLE);
            views.setViewVisibility(R.id.widget_list_view, View.GONE);
            appWidgetManager.updateAppWidget(appWidgetId, views);
            return;
        }
        //views.setViewVisibility(R.id.widget_fab, View.GONE);

        long updateInt = force ? 0 : plan_update;
        Log.d("WIDGET", "UPDATE FORCE: " + force);

        views.setTextViewText(R.id.widget_plan_empty, context.getString(R.string.plan_empty));

        views.setTextViewText(R.id.widget_title, context.getString(R.string.plan_loading));
        appWidgetManager.updateAppWidget(appWidgetId, views);

        plan.load(new SuccessCallback() {
            @Override
            public void callback(boolean success) {
                //views.setViewVisibility(R.id.widget_fab, View.VISIBLE);
                Log.d("WIDGET", "UPDATE COMPLETED: " + success);
                if (success) {
                    Date update = new Date();
                    update.setTime(plan.getTimestamp());
                    SimpleDateFormat format = new SimpleDateFormat("dd.MM. HH:mm", Locale.GERMANY);
                    String diff = format.format(update);
                    views.setTextViewText(R.id.widget_changed, context.getString(R.string.widget_last_update) + " " + diff);

                    views.setTextViewText(R.id.widget_title, plan.formatDate());
                    if (plan.getEntries().size() == 0) {
                        views.setViewVisibility(R.id.widget_plan_empty, View.VISIBLE);
                        views.setViewVisibility(R.id.widget_list_view, View.GONE);
                    } else {
                        views.setViewVisibility(R.id.widget_plan_empty, View.GONE);
                        views.setViewVisibility(R.id.widget_list_view, View.VISIBLE);
                    }
                    setRemoteAdapter(context, views, day.toString(), appWidgetId);
                    appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_list_view);
                }
                // Instruct the widget manager to update the widget
                appWidgetManager.updateAppWidget(appWidgetId, views);
            }
        }, force, updateInt);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // There may be multiple widgets active, so update all of them
        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }


    private static void setRemoteAdapter(Context context, @NonNull final RemoteViews views, String day, int appWidgetId) {
        Intent intent;
        switch (day) {
            default:
            case "today":
                intent = new Intent(context, VplanWidgetServiceToday.class);
                break;
            case "tomorrow":
                intent = new Intent(context, VplanWidgetServiceTomorrow.class);
                break;
        }
        intent.putExtra("day", day);
        intent.setData(Uri.fromParts("content", String.valueOf(appWidgetId), null));
        intent.putExtra("random", randomNum);
        randomNum++;
        views.setRemoteAdapter(R.id.widget_list_view, intent);
    }
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...