Доступ к БД с различными контекстами

Я возился с доступом к базе данных в 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.

Когда я пытаюсь получить доступную для записи базу данных с Context возвращенным с помощью getContext() , он просто терпит неудачу с NullPointerException . Он даже не начинает создавать базу данных. Симптомы возникают даже тогда, когда я удаляю код для тестовых линий getApplicationContext() .

Проблема здесь в том, что я пытаюсь написать код для получения запросов из базы данных в FileProvider , и я не могу получить доступ к getApplicationContext() из этого файла (он просто вызывает ошибку компилятора).

Если я делаю весь свой процесс в файле MainActivity.java, у меня нет ошибок (что плохо, я знаю, я делал это только для целей тестирования).

Мои вопросы:

  1. Как и в каком контексте я должен создавать свою базу данных?
  2. Почему я не могу использовать getApplicationContext() из FileProvider ?
  3. Могу ли я получить доступ к базе данных из другого контекста, который был создан? Насколько мне известно, база данных SQLite – это просто файл, созданный в файловой системе Android в собственной папке приложения. Какая разница в разных Context ?
  4. Почему я не могу создать базу данных в FileProvider.java с Context возвращаемым getContext() ?

–РЕДАКТИРОВАТЬ–

Вот 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() , я получаю пустой контекст. Вот почему получение ссылки db происходит неудачно в моем testDbAccess() .

То, что я сделал, я объявлял статический FileDbHelper (который расширяет SQLiteOpenHelper ) в моем классе FileProvider . Затем в 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 } } 

Это также отвечает на мои вопросы:

Как и в каком контексте я должен создавать свою базу данных?

  • Неважно, в каком контексте вы создаете свой db, вы можете получить к нему доступ, пока вы можете получить правильный контекст.

Почему я не могу использовать getApplicationContext() из FileProvider?

  • Оказалось, я могу. Правильный способ сделать это – getContext().getApplicationContext() но вам не нужно это делать, чтобы получить ссылку на db.

Могу ли я получить доступ к базе данных из другого контекста, который был создан?

  • Да, вы можете создать db в getApplicationContext() и получить доступ к нему в getContext()

Почему я не могу создать базу данных в файле FileProvider.java с контекстом getContext() ?

  • На самом деле вы можете, проблема была в основном вызвана тем, что вы не смогли получить доступ к самому контексту из новой тестовой функции, которую я написал. Не знаю почему, но это ситуация 🙂

Надеюсь, это поможет кому-то еще позже.

ОБНОВИТЬ

Важная информация о статических объектах и ​​утечке памяти.

M0skit0 предупреждал меня об утечке памяти, вызванной статическими объектами, которые ссылаются на контекст. Подробную информацию можно найти здесь . Вкратце, это говорит

Если вы планируете хранить долгоживущие объекты, которые нуждаются в контексте, запомните объект приложения. Вы можете легко получить его, вызвав Context.getApplicationContext () или Activity.getApplication ().

Поэтому будьте осторожны с этим. Обновлен фрагмент кода. Это спасло меня от много головной боли 🙂

Даже если вы уже ответили на свой вопрос, я хотел бы добавить некоторую информацию.

Методы getContext() и getApplicationContext() могут создавать getApplicationContext() NullPointerException , иногда классы просто не могут определить, что такое их собственный Контекст, и в этих ситуациях APP будет аварийно завершен.

Я думаю, что это хорошая идея явно передать контекст ContentProvider . Таким образом, вы можете гарантировать, что ваше приложение не сломается.

Например:

 public class FileProvider extends ContentProvider { Context context = null; public FileProvider(Context context){ this.context = context; } // Create static FileDbHelper private static FileDbHelper dbHelper; @Override public boolean onCreate() { if(this.context != null{ dbHelper = new FileDbHelper(this.context); }else{ // There is an error, notify the user and do something about it return false; } 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 provider = new FileProvider();

FileProvider provider = new FileProvider(this); Для деятельности

FileProvider provider = new FileProvider(getContext()); Для фрагментов (ведьк всегда имеет контекст)

По другим вопросам: нет разницы в том, какой класс базы данных работает. Контекст в основном предназначен для предоставления доступа к помощнику базы данных к устройству.

Intereting Posts
Как ограничить трансляцию своим собственным Android-приложением Цвет смены ящика навигации Несовместимость между гипервизором HAXM и VirtualBox 4.3.30+ Быстрое распознавание и отслеживание объектов в Android Как получить ограничение скорости с помощью Google Maps api? Как отключить мой диалог прогресса после загрузки webview? Приложение уже развернуто. Нет необходимости переустанавливать Что такое метод compat для использования finishAffinity () для API 14? Эффект Android-аудио ограничивает 5 диапазонов Как установить размер буфера кодировщика, созданный MediaCodec Код обнаружения Bluetooth / сканирования не работает после обновления Android 6 на моем Nexus 5 Реагировать на основе данных хранилища между сеансами Ошибка Qucikblox: для входа в твиттер на Android Как сделать изогнутую экранную клавиатуру для Android Проблема использования Android-приложений при установке приложений в неправильном порядке