ListView in widget adds randomly items on scrolling and resizing (nested remoteviews)

♀尐吖头ヾ 提交于 2019-11-29 03:36:42

Your thought behind ListView recycling issue is correct. You need to understand how things works at ground level.

MVC Pattern

The Android graphics works on the MVC pattern i.e. Model-View and Controller pattern. Model is your data, database in your case, View is your layout or graphical portion,such as ListView or RecyclerView or RemoteView. Controller changes your view after data update, parent View or ViewGroup in your case the RemoteViewsService.RemoteViewsFactory is the controller. I suggest to read further by googling the MVC model.

How Pattern is Implemented?

Any time the data changes, the view should be updated by the controller. The Android framework gives you opportunity to display your view at the given position with your data by overriding the getViewAt(int position).The controller calls the getViewAt(int position) to get the view at the given position in the ListView or RecyclerView. ListView or RecyclerView renders only visible rows on the screen. For example, If you have 100 items in the ListView and only 7 is visible on the screen than it will call getItemAt(int) 7 times. Every time you scroll the getItemAt(int) is called for the visible rows. The ListView and RemoteView take liberty to recycle/reuse the previously passed View returned by the getItemAt(int position). It ensures that memory consumed by graphical portion of your application is limited

Why there is strange behavior?

First of all every visible thing on the screen is a View such as TextView, ImageView and ListView etc. If not it can not be displayed on the screen. RemoteView is not a View. You pass the layout and data to be displayed with the RemoteView (View + Data).

Here the I am referring to your Screencast for the explanation.

1) Initialization: The ListView in your case, initially creates say 6 rows based on the visible space on screen and getViewAt(int position) is called once if getCount() returns 1. I request to check the return value of the getCount() of the List adapter.
2) You scrolled down: Nothing happens to the ListView and rendering of new Rows.
3) You Scrolled Up: getPositionAt(int position) is called again and RemoteView is passed back.Two rows are visible now. I request to check the getCount() return value. It should be 2 if not than the reason could be caching of rows by ListView.
4) You scrolled down: Nothing happens to the ListView and rendering of new Rows.
5) You Scrolled Up: Refer 3. The getCount() should be 3 and so on.

What you should do?

As per your implementation, you created the RemoteView only once and tried reusing the same view at the getItemAt(int) , may be to save on the layout inflation time.
To fix the issue, you MUST provide the FRESH RemoteView every time getItemAt(int) is called.

@Override
public RemoteViews getViewAt(int position) 
{
    Log.d("VplanWidgetViewsFactory", "getViewAt("+position+"):"+stunden.get(position));
    //TODO: Store context when constructor is called.
    RemoteView rv = new RemoteViews(context.getPackageName(), R.layout.fragment_stunde_widget);
    rv.setTextViewText(R.id.textView_lesson_nr, "" + (position + 1) + "."); <=  I have not tested this.

    return rv;
    //return stunden.get(position); <=COMMENT THIS
}

I found the answer myself.

To fix the problem with the weird adding of views on scrolling and resizing you have to call removeAllViews on the Layout where the subviews were added:

@Override
    public RemoteViews getViewAt(int position) {
        ...
        RemoteViews itemView = new RemoteViews(context.getPackageName(), R.layout.widget_listview_item);
        itemView.removeAllViews(R.id.linearLayout_item_body);
        ...
        return itemView;
    }

And the problem that the views are not displayed is because of the color: After adding

    subitem.setTextColor(R.id.textView_1, context.getResources().getColor(R.color.abc_primary_text_material_light));
    subitem.setTextColor(R.id.textView_2, context.getResources().getColor(R.color.abc_primary_text_material_light));
    subitem.setTextColor(R.id.textView_3, context.getResources().getColor(R.color.abc_primary_text_material_light));

all views are displayed:

Your problem seems to be in:

if(stundenContainer[j]!=null)
    Log.d("VplanWidgetViewsFactory", "stundenContainer["+j+"]:" + stundenContainer[j].toString());
else
    Log.d("VplanWidgetViewsFactory", "stundenContainer[" + j + "]:null");

if (stundenContainer[j] == null) {
    //Freistunde
    Log.d("VplanWidgetViewsFactory", "Freistunde");
    // HERE -----
    stunden.add(new RemoteViews(context.getPackageName(), R.layout.fragment_stunde_widget));
    faecher.add(new RemoteViews(context.getPackageName(), R.layout.fragment_fach));
    stunden.get(stunden.size() - 1).setTextViewText(R.id.textView_lesson_nr, "" + (j + 1) + ".");
 } else if (!stundenContainer[j].get(0).getSubject().equals("ignore")) {
     Log.d("VplanWidgetViewsFactory", "stundenContainer[j].get(0).getSubject(): " + stundenContainer[j].get(0).getSubject());
     // HERE -----
     stunden.add(new RemoteViews(context.getPackageName(), R.layout.fragment_stunde_widget));

You are adding it twice.. , but only when the first item is not ignored, so it appears random.

stunden.add(new RemoteViews(context.getPackageName(), R.layout.fragment_stunde_widget));
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!