Merging cursors during onLoadFinished() causes StaleDataException after rotation

谁都会走 提交于 2019-12-05 22:52:38

If you've started using swapCursor() instead of changeCursor() everywhere, then I hope you've also started handling cursor closing in those places.

changeCursor() will close the old cursor, this is intentional and works flawlessly when you're just directly using the cursor provided by onLoadFinished(). It is done this way so you don't have to worry about closing it.

When you rotate your device, the android system will check that the cursor it sent you last time has not yet been closed, and sends it again rather than spending resources on creating a new one. Your code wraps this cursor in a new instance of a MergeCursor which gets passed to changeCursor(), which sees that this is not the same object it got before, and decides to close the old instance. Since MergeCursor only wraps the cursors you pass it, rather than copying the data in them, your new instance now contains (at least) one closed cursor.

To correctly handle this you'll need to write some code of your own that checks if the cursor you get through onLoadFinished() is the same as one you have in your current MergeCursor instance, and only close the existing instance if you are getting a new cursor. Of course you'll also need to keep track of the other cursors wrapped in the same MergeCursor instance.

This issue came up again a couple of days ago and I was fortunate enough to stumble upon a solution.

I found out that I should have been using swapCursor() instead of changeCursor(). According to the Android docs:

Swap in a new Cursor, returning the old Cursor. Unlike changeCursor(Cursor), the returned old Cursor is not closed.

...

If the given new Cursor is the same instance is the previously set Cursor, null is also returned.

That last part seemed to be the key. The error mentioned in the question above could be traced back to the CursorAdapter choking on the merged cursor because it was closed when it tried to redraw the fragment after a rotation. By using swapCursor() instead, the CursorAdapter was able to reuse the "old" merged cursor instead of questioning its validity and throwing a StaleDataException.

I'm making some suppositions here; perhaps someone more knowledgeable in the inner-workings of Android could confirm or deny my reasoning.

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