更改ListView小部件的布局时保留滚动位置

时间:2017-04-17 21:33:51

标签: android listview android-widget

在更改窗口小部件中的ListView数据时,有没有办法保留滚动位置?

我目前正在使用此代码更新小部件的数据:

提供者:

public class OtpListWidgetProvider extends AppWidgetProvider {

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        for (final int widgetId : appWidgetIds) {
            final RemoteViews widget = getFirstWidget(context, widgetId);
            appWidgetManager.updateAppWidget(widgetId, widget);
        }
    }

    @Override
    public void onReceive(final Context context, final Intent intent) {
        super.onReceive(context, intent);
        if (OtpListWidgetService.ACTION_SHOW_CODE.equals(intent.getAction())) {
            int appWidgetId = intent.getIntExtra(
                    AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);

            final int codePosition = intent.getIntExtra(OtpListWidgetService.EXTRA_CODE_POSITION, 0);
            final Intent serviceIntent = new Intent(context, OtpListWidgetService.class)
                    .setAction(OtpListWidgetService.ACTION_SHOW_CODE)
                    .putExtra(OtpListWidgetService.EXTRA_CODE_POSITION, codePosition);
            // Intent.filterEquals doesn't take into account the extras on an Intent,
            // so we have to set its data.
            serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));

            Toast.makeText(context,
                    "Calling show with values codePosition=" + codePosition + " appWidgetId=" + appWidgetId,
                    Toast.LENGTH_SHORT).show();
            final RemoteViews widget = getWidgetWithAdapter(context, serviceIntent);
            AppWidgetManager.getInstance(context).partiallyUpdateAppWidget(appWidgetId, widget);
        }
    }

    private RemoteViews getFirstWidget(Context context, int widgetId) {
        final Intent serviceIntent = new Intent(context, OtpListWidgetService.class);
        final RemoteViews widget = getWidgetWithAdapter(context, serviceIntent);
        widget.setEmptyView(R.id.list_widget, android.R.id.empty);

        final Intent showCodeIntent = new Intent(context, OtpListWidgetProvider.class)
                .setAction(OtpListWidgetService.ACTION_SHOW_CODE)
                .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
        showCodeIntent.setData(Uri.parse(showCodeIntent.toUri(Intent.URI_INTENT_SCHEME)));
        final PendingIntent showCodeIntentTemplate =
                PendingIntent.getBroadcast(context, 0, showCodeIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        widget.setPendingIntentTemplate(R.id.list_widget, showCodeIntentTemplate);
        return widget;
    }

    private RemoteViews getWidgetWithAdapter(Context context, Intent serviceIntent) {
        final RemoteViews widget = new RemoteViews(context.getPackageName(), R.layout.list_widget);
        widget.setRemoteAdapter(R.id.list_widget, serviceIntent);
        return widget;
    }
}

服务:

public class OtpListWidgetService extends RemoteViewsService {
    public static final String ACTION_SHOW_CODE = "org.fedorahosted.freeotp.widget.ACTION_SHOW_CODE";
    public static final String EXTRA_CODE_POSITION = "EXTRA_CODE_POSITION";

    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {
        final OtpListWidgetViewsFactory factory = new OtpListWidgetViewsFactory(getApplicationContext());
        boolean shouldShowCode = ACTION_SHOW_CODE.equals(intent.getAction());
        if (shouldShowCode) {
            int codePosition = intent.getIntExtra(EXTRA_CODE_POSITION, 0);
            factory.setCodePositionToShow(codePosition);
        }
        return factory;
    }
}

RemoteViewFactory:

public class OtpListWidgetViewsFactory implements RemoteViewsService.RemoteViewsFactory {

    private final Context context;
    private final TokenPersistence persistence;
    private int showCodePosition;
    private boolean shouldShowCode;

    public OtpListWidgetViewsFactory(final Context context) {
        this.context = context;
        persistence = new TokenPersistence(context);
    }

    @Override
    public int getCount() {
        return persistence.length();
    }

    @Override
    public RemoteViews getViewAt(int position) {
        final Token token = persistence.get(position);
        final RemoteViews row = new RemoteViews(context.getPackageName(), R.layout.widget_row);

        try {
            Bitmap b = Picasso.with(context).load(token.getImage()).get();
            if (b == null) {
                row.setImageViewResource(R.id.widget_image, R.drawable.logo);
            } else {
                row.setImageViewBitmap(R.id.widget_image, b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        final String code;
        if (shouldShowCode && showCodePosition == position) {
            code = token.generateCodes().getCurrentCode();
        } else {
            code = "------";
        }
        row.setTextViewText(R.id.widget_code, code);
        row.setTextViewText(R.id.widget_issuer, token.getIssuer());
        row.setTextViewText(R.id.widget_label, token.getLabel());

        final Intent intent = new Intent();
        intent.putExtra(OtpListWidgetService.EXTRA_CODE_POSITION, position);
        row.setOnClickFillInIntent(R.id.widget_row_container, intent);
        return row;
    }

    public void setCodePositionToShow(int codePosition) {
        shouldShowCode = true;
        showCodePosition = codePosition;
    }

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

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

    @Override
    public void onCreate() {
        // no-op
    }

    @Override
    public void onDataSetChanged() {
        // no-op
    }

    @Override
    public void onDestroy() {
        // no-op
    }

    @Override
    public RemoteViews getLoadingView() {
        return null;
    }

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

现在发生了什么(在更新布局后,它会转到顶部,并保存滚动位置):

enter image description here

1 个答案:

答案 0 :(得分:0)

您应该拨打

,而不是调用新的Service来更新ListView的布局。
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.list_widget);

WidgetProvider中,并通过共享对象或字段将数据传递给RemoteViewsFactory