Hello, dear reader, hope you are Android Developer, or maybe you even work in the Android Framework Team? That would be nice.

Intro

We (Android Developers all over the world) use SQLiteDatabase as persistent storage for our apps and SQLiteDatabase.query() returns SQLiteCursor.

Problem

SQLiteCursor needs to be closed manually after we finish work with it, so we usually write such code everywhere:

Starting from API 16 Cursor implements Closeable interface and if you’re targeting >= Java 7 and your minSdk >= 16 (which is not true for many apps) you can use Try-With-Resources:

But, if you use ContentResolver, you should keep in mind that ContentResolver.query() may return null for incorrect request, and if you want to handle it, you need to request cursor, then check if it is null , and then use first variant of closing cursor (a lot of boilerplate code!).

Common problem: ListView or RecyclerView with Cursor in the adapter, when would you close it? I'd close it in Activity / Fragment onDestroy() but there are no guarantees that it would be called in case of process killing when Android needs memory for other apps, so why not just leave it to the GC?

Question

Why we have to manually close Cursors ?

We have Garbage Collection.

When you need cursor — you have a reference(s) to it.

When you don’t need cursor anymore — you don’t have a reference(s) to it and the cursor can be released.

Why Cursor just can’t be closed in Object.finalize() without logging a warning about leaking of it?

Solution

Close Cursor without warnings in Object.finalize() and allow to close it manually as we do it now.

If you didn’t know, SQLiteCursor already calls close() in SQLiteCursor.finalize().

Android Framework Team, can you please remove this annoying warning and allow us (in the documentation) to close it via GC?

But I heard that Object.finalize() is bad for releasing resources and almost any other things!

Yes and no. TL;TR: It’s okay to close SQLiteCursor in finalize() .

Object.finalize() may not be called in case of VM termination— yes, but as we all know, our Android App (process) can be killed at any time and your manual call to Cursor.close() might be skipped too. Call to Cursor.close() may slow down the GC Thread — yes. But where do we often close cursors that we use for list adapters? — On Main Thread, in some method of Activity/Fragment lifecycle — do you really care when you’ll have a pause on GC Thread or Main Thread? Also, Framework team may use some executor to close cursors in a separate thread and don’t pause the GC thread (it's possible to do without leaking cursor in finalize() . And if you need to manage it manually — just close them as you do it now (see 3). I am not talking about removing Cursor.close() because it’s important part of the API and we should be able to close Cursor at any time when we need it, but for most of the cases we can leave it to the GC. The only corner case I've found — full GC that may cause "stop the world" will be slower if cursors will be closed in Object.finalize() , but on the ART it should run full GC pretty rare.

You can also take a look at these articles:

Maybe you have some thoughts about this issue? Let's discuss it!

Comment from madisp — JRebel for Android :

The problem with gc isn't closing a single cursor. Imagine that by the time gc hits you can actually have more than a hundred. The other thing is that you don't really know what is backing that Cursor instance you get from the ContentResolver. Maybe it owns file handles. Maybe it owns a costly object in another proc, etc.

Holding hundred of Cursors in memory is bigger problem than this topic, but good point about different Cursor implementations which may lead slow down the GC thread.

Comment from Jake Wharton:

P.S. Managing resources in Java is like dealing with checked exceptions in places where you don’t want to deal with them, crazy combination — close() method that throws for example IOException , uh.

Probably, I've missed something and this is not a good solution, if so — please write a comment and describe "why?". Thanks for reading. Think about it!

https://twitter.com/artem_zin