Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Only in some phones, ListView not refresh after notifyDataSetChanged()

It is weirded because it happens only in some phones those resolution are FHD.

When UI is shown, everything seems ok. When I click items and call notifyDataSetChanged(), item won't refresh it's look. I need to click on the ListView anywhere again, the item will refresh layout to the correct look.

If the listview changes size (ex: search function will redesign whole layout), everything becomes OK.

Here is the ListView code:

public final class MyListView extends ListView implements AdapterView.OnItemClickListener
{

    ArrayList<SELECT_ITEM> selectList;
    ArrayList<ID_ITEM> idList;
    ShowItemAdapter showAdapter;

    public MyListView(Context context) 
    {
        selectList = new ArrayList<SELECT_ITEM>();
        idList = new ArrayList<ID_ITEM>();

        readIdList(mIdList);
        showAdapter = new ShowItemAdapter(context, idList, selectList);
        setAdapter(showAdapter);        

        ...
    }

    @Override
    protected void onFinishInflate() {
        setOnItemClickListener(this);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long ID) {
        boolean itemIsSelected = true;
        int size = selectList.size();

        // remove if click item in selectList
        for(int i=0 ; i<size ; i++) {
            int selectID = selectList.get(i).id;
            if (idList.get(position).id == selectID) {  
                itemIsSelected = false;
                selectList.remove(i);
                showAdapter.notifyDataSetChanged();
                break;
            }
        }

        if (itemIsSelected) {
            SELECT_ITEM item = new SELECT_ITEM();
            item.id = idList.get(position);
            selectList.add(item);
            // Here
            showAdapter.notifyDataSetChanged();
        }
    ...
    }

    ....
}

And here is Adapter code,

    public final class ShowItemAdapter extends BaseAdapter{

    public ArrayList<ID_ITEM>   mIdList;
    public ArrayList<SELECT_ITEM>   mSelectList;

    public ShowItemAdapter(Context context,
        ArrayList<ID_ITEM> idList,
        ArrayList<SELECT_ITEM> selectList)
    {
        mIdList = idList;
        mSelectList = selectList;
    }

    @Override
    public int getCount() {
        int ret = mIdList.size();
        return ret;
    }

    @Override
    public Object getItem(int position) {
        return position;
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ...

        for(int i=0 ; i<size ; i++)
        {
            // is selected
            if (mIdList.get(position).id == 
                selectList.get(i).id)
            {
                mIsSelected = true;
                break;
            }
        }

        if (mIsSelected)
        {
            textView.setBackgroundColor(Color.red);
        }
        else
        {
            textView.setBackgroundColor(Color.white);
        }
    }
}

Anybody give me a hand?

I found those phones work correctly will cause the same issue when debugging pause at getView(). I think .. it is like "Views has been updated so it won't refresh views." But views update during debugging make the ui not refresh actually, then it works in the wrong way.

I guess this is about refreshing views.

like image 754
timyau Avatar asked Jun 04 '15 02:06

timyau


1 Answers

I see a possible code conflict and a timing issue between getView() of the adapter and the onItemClick().

Allow me to explain. In getView(), there is code

if (mIdList.get(position).id == selectList.get(i).id)

Note: This checks the value of selectList, which is not even declared in this Adapter class. I assume you meant mSelectList. But let's move on...

In onItemClick(), there is code

if (idList.get(position).id == selectID) {  
   ...
   selectList.remove(i);
   ...

Note: This code removes an item from selectList, while in getView(), it is checking for the same object. We cannot know which code will run first. But I have an idea... getView() is a virtual callback method where the BaseAdapter may trigger the method when it requires a row or item to display. So when you remove an item from a Listview, the Adapter may not request a refresh, no matter what you do in code. And the adapter ShowItemAdapter is responsible for all row/views refresh.

Suggestion: Place the same code (for remove/add item) in getView() to avoid these kind of code conflicts.

Let us know and good luck with this odd anomaly.
Tommy Kwee

like image 185
The Original Android Avatar answered Dec 11 '22 08:12

The Original Android