android - 访问具有不同上下文的数据库

标签 android nullpointerexception android-sqlite android-context

我正在摆弄 Android 中的数据库访问以了解事情是如何处理的。

我的 MainActivity.java 文件中有以下代码:

Log.v("test db acc", "start getApplicationContext test");
FileDbHelper dbHelper1 = new FileDbHelper(getApplicationContext());
SQLiteDatabase db1 = dbHelper1.getWritableDatabase();
Log.v("test db acc", "success getApplicationContext test");

Log.v("test db acc", "start getContext test");
FileProvider provider = new FileProvider();
provider.testDbAccess();
Log.v("test db acc", "success getContext test");

这是 provider.testDbAccess() 函数的定义:

FileDbHelper dbHelper2 = new FileDbHelper(getContext());
SQLiteDatabase db2 = dbHelper2.getWritableDatabase();

第一次尝试访问数据库成功,没有任何错误。如果数据库不存在,它会创建它,我可以在创建 db1 对象后查询和写入数据。

当我尝试通过 getContext() 返回的 Context 获取可写数据库时,它只是失败并出现 NullPointerException。它甚至没有开始创建数据库。即使我删除了 getApplicationContext() 测试行的代码,也会出现症状。

这里的问题是,我正在尝试编写代码以从 FileProvider 中的数据库获取查询,但我无法从该文件访问 getApplicationContext()(它只会引发编译器错误)。

如果我在 MainActivity.java 文件中执行我的所有过程,我没有错误(我知道这不好,我这样做只是为了测试目的)。

我的问题是:

  1. 我应该如何以及在什么情况下创建我的数据库?
  2. 为什么我不能使用 FileProvidergetApplicationContext()
  3. 我可以从创建数据库的另一个环境访问数据库吗?据我所知,SQLite 数据库只是在应用程序自己的文件夹中的 android 文件系统中创建的一个文件。不同的 Context 有什么区别?
  4. 为什么我不能在 FileProvider.java 中使用 getContext() 返回的 Context 创建数据库?

--编辑--

这是错误的 logcat:

08-02 16:03:55.628 7614-7614/com.permasse.apps.file.android E/AndroidRuntime: FATAL EXCEPTION: main
            java.lang.RuntimeException: Unable to resume activity {com.permasse.apps.file.android/com.permasse.apps.file.android.MainActivity}: java.lang.NullPointerException
                at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2575)
                at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603)
                at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2089)
                at android.app.ActivityThread.access$600(ActivityThread.java:130)
                at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
                at android.os.Handler.dispatchMessage(Handler.java:99)
                at android.os.Looper.loop(Looper.java:137)
                at android.app.ActivityThread.main(ActivityThread.java:4745)
                at java.lang.reflect.Method.invokeNative(Native Method)
                at java.lang.reflect.Method.invoke(Method.java:511)
                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
                at dalvik.system.NativeStart.main(Native Method)
             Caused by: java.lang.NullPointerException
                at com.permasse.apps.file.android.FileProvider.testDbAccess(FileProvider.java:120)
                at com.permasse.apps.file.android.MainActivity.onResume(MainActivity.java:32)
                at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1184)
                at android.app.Activity.performResume(Activity.java:5082)
                at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2565)
                at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603) 
                at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2089) 
                at android.app.ActivityThread.access$600(ActivityThread.java:130) 
                at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195) 
                at android.os.Handler.dispatchMessage(Handler.java:99) 
                at android.os.Looper.loop(Looper.java:137) 
                at android.app.ActivityThread.main(ActivityThread.java:4745) 
                at java.lang.reflect.Method.invokeNative(Native Method) 
                at java.lang.reflect.Method.invoke(Method.java:511) 
                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 
                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
                at dalvik.system.NativeStart.main(Native Method) 

这里是 FileProvider.java 的相关部分。原始代码包括查询生成器、uri 匹配器等。我简化了代码以隔离问题。

public class FileProvider extends ContentProvider {

    private FileDbHelper dbHelper;

    @Override
    public boolean onCreate() {
        dbHelper = new FileDbHelper(getContext());
        return true;
    }

    public void testDbAccess() {

        SQLiteDatabase db = dbHelper.getWritableDatabase(); //Line no 120

    }

}

和MainActivity.java

public class MainActivity extends AppCompatActivity{

    @Override
    protected void onResume() {
        super.onResume();

        FileProvider provider = new FileProvider();

        provider.testDbAccess(); //Line no 32

    }
}

最佳答案

虽然我不确定为什么会这样,但是我解决了这个问题。

在我的 FileProvider 类(它扩展了 ContentProvider)中,如果我尝试 getContext() 除了 onCreate() 方法,我得到一个空的上下文。这就是为什么在我的 testDbAccess() 方法上获取数据库引用失败的原因。

我所做的是在我的 FileProvider 类中声明了一个静态的 FileDbHelper(它扩展了 SQLiteOpenHelper)。然后在 onCreate() 方法中,我创建了具有适当上下文的 FileDbHelper 类。因为它是静态的,所以我现在可以稍后在同一个类的任何地方使用这个对象。现在看起来有点像这样:

public class FileProvider extends ContentProvider {

    // Create static FileDbHelper
    private static FileDbHelper dbHelper;

    @Override
    public boolean onCreate() {

        // We can only access the context from onCreate() function, so we 
        // instantiate it here to use later on. 
        dbHelper = new FileDbHelper(this.getContext().getApplicationContext);
        // Important explanation about context in bottom of the answer!!


        return true;
    }

    // Then I can use it like this: 
    public void testDbAccess() {

        // dbHelper was staticly declared within class and instantiated already
        SQLiteDatabase db = dbHelper.getWritableDatabase(); 

        // Then do whatever you want to do with the code

    }
}

这也回答了我的问题:

我应该如何以及在什么情况下创建我的数据库?

  • 在哪个上下文中创建数据库并不重要,只要您可以获得适当的上下文,就可以访问它。

为什么我不能使用 FileProvider 的 getApplicationContext()

  • 事实证明我可以。执行此操作的正确方法是 getContext().getApplicationContext() 但您不必为了获得对数据库的引用而这样做。

我可以从创建数据库的另一个上下文访问数据库吗?

  • 是的,您可以在 getApplicationContext() 中创建数据库并在 getContext() 中访问它

为什么我不能使用 getContext() 上下文在 FileProvider.java 文件中创建数据库?

  • 实际上可以,问题基本上是由于无法从我编写的新测试函数访问上下文本身引起的。不知道为什么,但情况就是这样 :)

希望以后对其他人有所帮助。

更新

有关静态对象和内存泄漏的重要信息。

m0skit0警告我有关由持有上下文引用的静态对象引起的内存泄漏。可以查到详细资料here .简而言之,它说

If you plan on keeping long-lived objects that need a context, remember the application object. You can obtain it easily by calling Context.getApplicationContext() or Activity.getApplication().

所以要小心那个。相应地更新了代码 fragment 。这让 future 的我免于头痛 :)

关于android - 访问具有不同上下文的数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38716987/

相关文章:

java - 为什么 Java 编译器允许在三元运算符中将 null 转换为原始类型

java - 空指针协助。

java - ArrayList 给出空指针异常

Android db文件被复制但无法打开

java - 从 SQLITE 数据库表中提取整数时出现数字格式异常

android - AlertDialog 样式和颜色

android - 歌曲识别算法

Android 构建因 kotlin-reflect 和 proguard 而失败

android - 调整视频大小以适合 VideoView

android-sqlite - 通过从断言复制数据库文件在 Room 中使用预填充的数据库