【问题标题】:super.getWritableDatabase() crashes when called from MyApplication that's in Library Project从库项目中的 MyApplication 调用 super.getWritableDatabase() 时崩溃
【发布时间】:2011-11-04 17:10:27
【问题描述】:

我确实有几个以相同方式设计的应用程序。扩展的 Application 持有数据库连接,扩展的 SQLiteOpenHelper 拥有所有代码。

在标准的 android 项目中使用时有效。

当扩展应用程序位于库项目中时,它会崩溃。

以下代码是扩展的应用程序类。它位于图书馆项目中。如果在库项目中使用它会崩溃,但如果它是没有库项目的标准 Android 应用程序的一部分,则不会崩溃。我试图将 MyApplication 类从 Library Project 移到 Project 中(更改 Manifest 中的名称) - 没有成功。

我的猜测,但我只是在这里钓鱼,是 MySQLiteOpenHelper 使用库项目的权限/权限/位置,而不是项目本身。

public class MyApplication extends Application {

    private static SQLiteDatabase     sqliteDatabase;
    private static MySQLiteOpenHelper sqliteOpenHelper;

    public static SQLiteDatabase getSqliteDatabase() {
        return sqliteDatabase;
    }

    public static MySQLiteOpenHelper getSqliteOpenHelper() {
        return sqliteOpenHelper;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        MyPreferenceActivity.createSettings(getApplicationContext());

        sqliteOpenHelper = new MySQLiteOpenHelper(getApplicationContext());
        if (sqliteOpenHelper != null) {
            sqliteDatabase = sqliteOpenHelper.getWritableDatabase();
        }
    }
}

这是扩展 SQLiteOpenHelper 类的一部分:

public class MySQLiteOpenHelper extends SQLiteOpenHelper {

    private static final int      DATABASEVERSION = 18;
    private static final String   DATABASENAME = "myproduct.db";

    private Context               context;
    private SQLiteDatabase        sqliteDatabase;
    private String                location; 

    public MySQLiteOpenHelper(final Context context) {
        super(context, DATABASENAME, null, DATABASEVERSION);

        this.context = context;
    }

    @Override
    public SQLiteDatabase getWritableDatabase() {
            ...
    try {
        if (Tools.isSDCardWriteable() && (fileSdDbDir.exists() || fileSdDb.exists())) {
            // Database on SD-card works perfect
            // If I use this to create the internal database it fails here too
            location = sdDb;
            sqliteDatabase = SQLiteDatabase.openOrCreateDatabase(location, null);

            int version = sqliteDatabase.getVersion();

            if (version != DATABASEVERSION) {
                sqliteDatabase.beginTransaction();

                try {
                    if (version == 0) {
                        onCreate(sqliteDatabase);
                    } else {
                        onUpgrade(sqliteDatabase, version, DATABASEVERSION);
                    }

                    sqliteDatabase.setVersion(DATABASEVERSION);
                    sqliteDatabase.setTransactionSuccessful();
                } finally {
                    sqliteDatabase.endTransaction();
                }
            }

            onOpen(sqliteDatabase);
        } else {
            // internal database fails to create
            location = intDb;
            sqliteDatabase = super.getWritableDatabase(); <-- fails
        }
    } catch (Exception exception) {
    if (MyPreferenceActivity.DEBUG) Log.d("Exception", exception.getMessage()); <-- crashes
    }

    return sqliteDatabase;
    }

    @Override
    public void onCreate(final SQLiteDatabase sqliteDatabase) {
        //
    }

    @Override
    public void onUpgrade(final SQLiteDatabase sqliteDatabase, final int oldVersion, final int newVersion) {
        //
    }

    ...
}

这是图书馆项目的清单:

<?xml version="1.0" encoding="utf-8"?>

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="xxx.yyy.zzzlib.android" >

    <uses-sdk
        android:minSdkVersion="7"
        android:targetSdkVersion="11" />
</manifest>

这是项目清单的一部分:

<?xml version="1.0" encoding="utf-8"?>

    <manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:installLocation="preferExternal" 
        android:versionCode="41"
        android:versionName="5.0.3"
        package="xxx.yyy.zzz.android" >

        <application
            ...
            android:name="xxx.yyy.zzzlib.android.MyApplication" >
            ...
        </application>

        ...

        <uses-sdk
            android:minSdkVersion="7"
            android:targetSdkVersion="11" />
    </manifest> 

我不知道为什么这不起作用。也许是上下文的事情,但错误指向文件。我没有任何线索。

这种方法有问题吗?它在标准的 Android 项目环境中运行完美。

非常感谢。

编辑:

Stacktrace 在 Log.d 中显示崩溃,但失败的是数据库调用:

11-04 17:53:56.143: E/AndroidRuntime(1127): FATAL EXCEPTION: main
11-04 17:53:56.143: E/AndroidRuntime(1127): java.lang.RuntimeException: Unable to create application xxx.yyy.zzzlib.android.MyApplication: java.lang.NullPointerException: println needs a message
11-04 17:53:56.143: E/AndroidRuntime(1127):     at android.app.ActivityThread.handleBindApplication(ActivityThread.java:3275)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at android.app.ActivityThread.access$2200(ActivityThread.java:117)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:969)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at android.os.Handler.dispatchMessage(Handler.java:99)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at android.os.Looper.loop(Looper.java:130)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at android.app.ActivityThread.main(ActivityThread.java:3683)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at java.lang.reflect.Method.invokeNative(Native Method)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at java.lang.reflect.Method.invoke(Method.java:507)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at dalvik.system.NativeStart.main(Native Method)
11-04 17:53:56.143: E/AndroidRuntime(1127): Caused by: java.lang.NullPointerException: println needs a message
11-04 17:53:56.143: E/AndroidRuntime(1127):     at android.util.Log.println_native(Native Method)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at android.util.Log.d(Log.java:137)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at xxx.yyy.zzzlib.android.MySQLiteOpenHelper.getWritableDatabase(MySQLiteOpenHelper.java:1493)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at xxx.yyy.zzzlib.android.MyApplication.onCreate(MyApplication.java:27)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:969)
11-04 17:53:56.143: E/AndroidRuntime(1127):     at android.app.ActivityThread.handleBindApplication(ActivityThread.java:3272)

【问题讨论】:

  • 这一行是什么:11-04 17:53:56.143: E/AndroidRuntime(1127): at xxx.yyy.zzzlib.android.MySQLiteOpenHelper.getWritableDatabase(MySQLiteOpenHelper.java:1493) 调用 Log?
  • 失败的是调用“super.getWritableDatabase()”的行。崩溃来自 Log.d 在异常消息中没有任何数据,但它是失败的数据库调用。我确实编辑了我的帖子。它现在显示了大部分扩展的 getWritableDatabase() 和堆栈跟踪。非常感谢。
  • 所以你调用getWritableDatabase(),它失败并抛出你捕获的异常,然后你在日志中看到上面的stacktrace?
  • 没错。正如我所说,失败的是数据库调用。这就是我试图描述的问题。这种精确的代码设计(完整的 MyApplication、MySQLiteOpenHelper.getWriteableDatabase()、...)是 10 多个应用程序的一部分。仅在此代码(MyApplication、MySQLiteOpenhelper)是库的一部分和独立 Android 项目的一个应用程序中失败。
  • 好的,你抓到吃的例外是什么?在您的 catch 块中放置一个断点并进行调试,或者只是完全删除 catch 块并让崩溃并发布(现在)未处理的异常。

标签: android library-project sqliteopenhelper


【解决方案1】:

1) 发布更多堆栈跟踪。上下文很少。 2) 'if (sqliteOpenHelper != null) {' 不需要。它永远不会为空。 3) 覆盖 getWritableDatabase 没有任何意义,至少在这种情况下是这样。我不会这样做。 4) 你的助手类的 onCreate 是空的。我猜你在公开发帖之前就这样做了?

如果您的助手类尝试从 LIBRARY 包中给出的路径打开数据库,我可以看出这会有多麻烦。不确定文件权限如何与库项目一起使用。

【讨论】:

  • 感谢您的回答。是的,代码已从 onCreate()/onUpgrade() 中删除。我使用 getWriteableDatabase() 是因为 try{} 块上方是一个 if() 语句,我在其中选择 SD 卡上的数据库和内部数据库。显示的是内部数据库的部分。这个崩溃了。如果我使用外部存储,则创建数据库。我将在一分钟内编辑我的问题并添加堆栈跟踪和 if。
  • 请发布此行:MySQLiteOpenHelper.java:1493 及周边行。实际的异常与数据库无关。 可能最初是由数据库引起的,但您的实际异常是由于日志语句中的 null 引起的。
  • 是的,Log.d 崩溃了,但 super.getWritableDatabase 失败了。我确实编辑了我的问题以显示大部分内容。有趣的部分是 a.) 在 SD 卡上创建数据库时它可以工作,b.) 如果调用 super.getWritableDatabase() 在 else 部分的内部存储上创建数据库,它会失败,c.) 如果使用该部分用于创建内部数据库的外部数据库在这里也失败了。所以它必须与内部存储有关。仅当代码位于库项目中时才会发生这种情况...
  • 您需要实际的堆栈跟踪。我的猜测是文件权限问题。此外,请确保您传入的任何“上下文”都来自正在运行的应用程序,而不是来自库代码。这应该得到正确的包/路径(也许)。
  • Context 来自 Application 中的 onCreate(),并通过 getApplicationContext() 检索。这个上下文被传递给 SQLiteOpenHelper 的构造函数并在那里到处使用。 Application 和 SQLiteOpenHelper 在一个库项目中。应用程序在使用该库的应用程序清单中是完全合格的(例如 android:name="xxx.yyy.zzzlib.android.MyApplication")。这可能是问题的一部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多