Search code examples
androidandroid-listviewandroid-contentproviderandroid-loadermanager

Android Bug? Wrong row starts animating on ListView after DB update during Item animation of the correct item


I have a ListView which is taking data from DB. Each row when clicked animates to the right and back as follows:

@Override
    public void onItemClick(AdapterView<?> av, View v, int pos, long id) {

...
          pos = pos - mList.getFirstVisiblePosition();
          mList.getChildAt(pos).startAnimation(anim );
...}

the animation lasts about 1sec and is : slide out right then slide in back

This part works fine if there is no interaction with DB during the animation

Now, each item from the list has a counter in DB. Whenever user clicks on the item from the list the counter should be increased in DB and that is visually presented on the ListView per item as well.

So, DB is visible through ContentProvider

This is the issue :

Whenever I click on an item the animation starts, and then the update is performed to DB through ContentResolver. The problem is that the animation starts at the proper element but just right after it starts it suddenly stops and is finished on other element from the list.

So if I have four elements on the list

----------1----------
----------2----------
----------3----------
----------4----------

and I click element 1, number 1 starts sliding right but after around 200ms it stops and element 4 continues to animate from the place where 1 stopped for the rest of the animation

Same can be reproduced if I press 2 but this time number 3 finishes animation. If 3 then 2 finishes. If I click 4 then 1.

Assuming only 4 items are visible I can reproduce it throught whole list.

It is always the opposite element. I debug the position in onItemClick, but it is always right.

IMPORTANT When I comment out the code that makes the update in DB, everything works fine. Which suggests that the problem occurs when SimpleCursorAdapter of ListView is refreshed with new Cursor through LoaderManager from the DB during the animation.

WHAT I did try using CommonsWare Loaderex instead of ContentProvider. It gives the same effect.

CODE SNIPPETS

public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
  return new CursorLoader(this.getActivity(), MyContentProvider.CONTENT_URI,
            new String[]{}, "uid>0 AND distance<80000", null, "distance LIMIT 100");
}


public void onLoadFinished(Loader<Cursor> ld, Cursor c) {
    merchantAdapter.swapCursor(c);
}

OnItemClick has this code :

ContentResolver cr = getActivity().getContentResolver();
                ContentValues cv = new ContentValues();
                cv.put("counter", counter);
                Uri mUri = ContentUris.withAppendedId(MyContentProvider.CONTENT_URI, uid);
                cr.update(mUri, cv, null, null);

What also bugs me that I wasnt able to make the LoaderManager update the list for me automatically so after above cr.update(...

I do this to refresh the list after each update

getActivity()).lm.getLoader(0).forceLoad();

Could the animation problem be Android bug? or what I am missing?

Current idea to solve this I guess my option is to block clicks for animation duration and make cr.update in handler after animation duration has passed so that the refresh will not affect animation.

Please advise


Solution

  • I can now confirm that : the behaviour only happens on my 2.2 device. And it can be reproduced. It works fine (the animation finishes properly when rows are updated in the bg) on Android 4.1 device and it can be reproduced.

    My current solution to this is Since I want to support 2.2 devices. I create listener to this animation. when anim is finished I make the update to db. Also I block UI for the duraiton of anim (it is around 300ms so its fine)

    NOTE - this does look like Android SDK problem

    As for the update problem and using forceLoad In my content provider implementation I had to add this inside my query method :

    cursor.setNotificationUri(getContext().getContentResolver(), uri);
    

    which is registering this uri to ContentResolver. now it works fine without using forceLoad