7

Getting this error when I use SQLiteDatabase as a Closeable

I've got a sample project to recreate it:

https://github.com/blundell/SQLDatabaseError

With a class that extends SQLiteOpenHelper:

public class DatabaseHelper extends SQLiteOpenHelper {

....

public void openAndCloseDatabase() {
    SQLiteDatabase database = getWritableDatabase();

    close(database);
}

private void close(Closeable database) {
    try {
        if (database != null) {
            database.close();
        }
    } catch (Exception e) {
        Log.e("Error", "Oh no!", e);
    }
}

}

Stack trace:

12-14 12:23:43.719: E/AndroidRuntime(5179): FATAL EXCEPTION: main
12-14 12:23:43.719: E/AndroidRuntime(5179): java.lang.IncompatibleClassChangeError: interface not implemented
12-14 12:23:43.719: E/AndroidRuntime(5179):   at com.blundell.sqldatabasecursorerror.DatabaseHelper.close(DatabaseHelper.java:35)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at com.blundell.sqldatabasecursorerror.DatabaseHelper.openAndCloseDatabase(DatabaseHelper.java:29)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at com.blundell.sqldatabasecursorerror.MainActivity.onCreate(MainActivity.java:13)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1623)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1675)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at android.app.ActivityThread.access$1500(ActivityThread.java:121)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:943)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at android.os.Handler.dispatchMessage(Handler.java:99)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at android.os.Looper.loop(Looper.java:130)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at android.app.ActivityThread.main(ActivityThread.java:3701)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at java.lang.reflect.Method.invokeNative(Native Method)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at java.lang.reflect.Method.invoke(Method.java:507)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)
12-14 12:23:43.719: E/AndroidRuntime(5179):     at dalvik.system.NativeStart.main(Native Method)

API:

http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html

http://developer.android.com/reference/android/database/sqlite/SQLiteClosable.html

http://developer.android.com/reference/java/io/Closeable.html

This should work shouldn't it?

 public final class SQLiteDatabase extends SQLiteClosable
 >>
 public abstract class SQLiteClosable extends Object implements Closeable
 >>
 public interface Closeable

Doesn't work:

  • Xperia Play Android 2.3.4
  • Motorola Xoom Android 4.0.4

Does work:

  • Samsung Galaxy Nexus Android 4.2
4
  • public class DatabaseHelper extends SQLiteOpenHelper implements Closeable is possible too. Commented Dec 14, 2012 at 12:44
  • 1
    (not an Android developer) IncompatibleClassChangeError sounds like you're compiling and running against different versions of the library. Commented Dec 14, 2012 at 12:45
  • See the accepted answer here: stackoverflow.com/questions/1980452/… Commented Dec 14, 2012 at 12:45
  • 1
    @ignis and Anders: yeah, but those interfaces have been in there since API Level 1, and I would think that Android guarantees binary upwards compatibility. Weird... Commented Dec 14, 2012 at 12:49

1 Answer 1

7

Okay, found the problem in the Change Notes for 4.1 (API Level 16):

android.database.sqlite.SQLiteClosable implements java.io.Closeable only from API Level 16. Before that, they were unrelated (even though both interfaces existed since the beginning).

So you should use SQLiteClosable directly if you want your code to be backwards compatible.

It is also probably worthwhile to install the SDK for the lowest version you want to support and try to build with it, then this would have been detected by the compiler.

Sign up to request clarification or add additional context in comments.

4 Comments

Would be nice if this was noted in the Javadoc for SQLiteClosable somewhere, too.
Thanks, good spot! Shame it's from api16 more safety check code to write. Yeah Lint normally catches obvious API level reqs, but as you say they are both available from API 1. Might create a Lint warning and push it up.
Just been bitten by this again! This time with java.util.Scanner developer.android.com/sdk/api_diff/19/changes/…
How come Lint API checker didn't catch this?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.