Android Widget getViewAt被调用了太多次

时间:2015-03-26 10:13:17

标签: android widget

我正在开发一个小部件的问题。它是由内容提供商支持的简单列表视图。问题是方法0的方法getViewAt()被调用了两次。这是代码和日志。

Widget Xml提供程序:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="120dp"
android:minHeight="160dp"
android:updatePeriodMillis="86400000"
android:initialLayout="@layout/calendar_appwidget"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen|keyguard">

小工具服务

...
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
    return new CalendarRemoteViewsFactory(this.getApplicationContext(),intent);
}
...

    @Override
    public void onCreate() {

        readDateFormat(mContext);
        simpleDateFormat = new SimpleDateFormat(datePattern, Locale.US);

        mCal = Calendar.getInstance();


    }

    @Override
    public RemoteViews getViewAt(int i) {

        RemoteViews rv = new RemoteViews(mContext.getPackageName(),R.layout.calendar_widget_item);

        Log.d("Widgets","Get view at "+i);

        UpcomingShow show = (UpcomingShow)items.get(i);

        mCal.setTime(getShowDay(show.getAirs_at()));
        int dayOfMonth = mCal.get(Calendar.DAY_OF_MONTH);

        if (mLastDay != dayOfMonth){
            mLastDay = dayOfMonth;
            rv.setTextViewText(R.id.day,String.valueOf(dayOfMonth));
            rv.setViewVisibility(R.id.day, View.VISIBLE);
        }else
            rv.setViewVisibility(R.id.day, View.INVISIBLE);

        rv.setTextViewText(R.id.title, show.getShow().getTitle());

        try {
            Date showDate = loadDate(show.getAirs_at(), datePattern);

            simpleDateFormat.applyPattern(timeFormat == Utils.TimeFormat.CLOCK_24H ? "k:mm" : "h:mm a");
            simpleDateFormat.setTimeZone(mTimeZone);
            rv.setTextViewText(R.id.date,simpleDateFormat.format(showDate) + " on " + show.getShow().getNetwork());

        } catch (Exception e) {
            e.printStackTrace();
        }

        //Episode
        String episodeStr = show.getEpisode().getSeason() + "x" + show.getEpisode().getNumber() + " " + show.getEpisode().getTitle();
        rv.setTextViewText(R.id.episode,Utils.getTextInBold(episodeStr, 0, episodeStr.indexOf(" "), Spanned.SPAN_INCLUSIVE_EXCLUSIVE));

        return rv;
    }

    @Override
    public int getCount() {
        return items != null ? items.size() : 0;
    }

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

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

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

    @Override
    public void onDataSetChanged() {

        final long identityToken = Binder.clearCallingIdentity();

        pos = 0;

        Log.d("Widgets","OnDataSetChanged");
        String selection = DataProviderContract.Upcoming.COLUMN_AIRS_AT + " >= " + mCal.getTimeInMillis();
        try {
            mCursor = mContext.getContentResolver().query(
                    DataProviderContract.Upcoming.CONTENT_URI,
                    null,
                    selection,
                    null,
                    DataProviderContract.Upcoming.COLUMN_AIRS_AT + " ASC "
            );

            if (items!=null && items.size()>0)
                items.clear();

            items = getShowsFromCursor(mCursor);

            if (mCursor!=null && !mCursor.isClosed())
                mCursor.close();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            Binder.restoreCallingIdentity(identityToken);
        }



    }

窗口小部件提供程序

public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    final int N = appWidgetIds.length;


    // Perform this loop procedure for each App Widget that belongs to this provider
    for (int i=0; i<N; i++) {

        // Set up the intent that starts the StackViewService, which will
        // provide the views for this collection.
        Intent intent = new Intent(context, CalendarWidgetService.class);
        // Add the app widget ID to the intent extras.
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
        intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));


        // Instantiate the RemoteViews object for the app widget layout.
        RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.calendar_appwidget);
        // Set up the RemoteViews object to use a RemoteViews adapter.
        // This adapter connects
        // to a RemoteViewsService  through the specified intent.
        // This is how you populate the data.
        rv.setRemoteAdapter(appWidgetIds[i], R.id.list, intent);

        //Calls update
        appWidgetManager.updateAppWidget(appWidgetIds[i], rv);

    }

    super.onUpdate(context, appWidgetManager, appWidgetIds);
}

logcat的

03-26 10:02:54.011    1781-1792/com.D/Widget﹕ Acaba o parse com: 5
03-26 10:02:54.019    1781-1791/com.D/Widgets﹕ Get view at 0
03-26 10:02:54.027    1781-1792/com.D/Widgets﹕ Get view at 0
03-26 10:02:54.031    1781-1792/com.D/Widgets﹕ Get view at 1
03-26 10:02:54.031    1781-1792/com.D/Widgets﹕ Get view at 2
03-26 10:02:54.035    1781-1792/com.D/Widgets﹕ Get view at 3
03-26 10:02:54.039    1781-1792/com.D/Widgets﹕ Get view at 4

PS: 小部件布局

<?xml version="1.0" encoding="utf-8"?>
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@color/background"
android:dividerHeight="0dp"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/list"/>

正如你所看到的那样,方法被调用了两次pos 0并且有时跳转位置,比如getViewAt(1) - &gt; getViewAt(3) - &gt; getViewAt(2)。我不知道为什么会这样。我做错了什么。

Teste with 5.0.2,4.4.4,4.1.1

由于

2 个答案:

答案 0 :(得分:1)

为了提高效率,ListView没有特定的顺序来调用位置,并且可以调用相同的位置两次或更多。这是预期的行为。

答案 1 :(得分:0)

好吧,也许你应该让你的getItemId()至少返回位置而不是全部0.但这可能不是你问题的原因。

事实上,我相信Android并不保证调用getViewAt()的顺序或时间。这不是你的错。更糟糕的是,在我的制作应用程序中,有时我遇到的情况是我的位置与我的尺寸相同,所以我崩溃了。

所以我的建议是,您可以安全地忽略调用的顺序或次数,并且应该防止错误的位置:检查对getViewAt()getItemId()的调用,并使其返回null或-1。