Accessing hidden method android database sqlite sqlitedatabase

Правильная работа с БД в Android

Приветствую всех дроидеров в эти непростые для нас времена.
Честно говоря, заколебала эта шумиха о патентах, войнах и т.д., но в данной статье речь пойдет не об этом.
Я не собирался писать статью на данную тему, так как везде всего полно о работе с базой данных в Android и вроде бы все просто, но уж очень надоело получать репорты об ошибках, ошибках специфичных и связанных с БД.
Поэтому, я рассматрю пару моментов с которыми я столкнулся на практике, чтобы предостеречь людей, которым только предстоит с этим разбираться, а дальше жду ваших комментариев на тему решения указанных проблем после чего внесу изменения в пост и мы сделаем отличный туториал, который будет образцом работы с SQLite в Android не только для начинающих, но и для тех, кто уже знаком с основами и написал простые приложения.

Способы работы с БД

Существует три способа работы с данными в БД, которые сразу бросаются на ум:
1) Вы создаете пустую структуру базы данных. Пользователь работает с приложением(создает заметки, удаляет их) и база данных наполняется. Примером может служить приложение NotePad в демо-примерах developer.android.com или на вашем дроид-девайсе.
2) Вы уже имеете готовую БД, наполненную данными, которую нужно распространять с приложением, либо парсите данные из файла в assets.
3) Получать данные из сети, по мере необходимости.
Если есть какой-то еще один или два способа, то с радостью дополню данный список с вашей помощью.
Все основные туториалы расчитаны как раз на первый случай. Вы пишите запрос на создание структуры БД и выполняете этот запрос в методе onCreate() класса SQLiteOpenHelper, например так:

Примерно так. Более полный вариант класса и других составляющих можно посмотреть по ссылке внизу статьи.
Дополнительно можно переопределить методы onOpen(), getReadableDatabase()/getWritableDatаbase(), но обычно хватает того, что выше и методов выборки данных.
Далее, экземпляр этого класса создаем в нашем приложении при его запуске и выполняем запросы, то бишь проблемная часть пройдена. Почему она проблемная? Потому что, когда пользователь качает приложения с маркета, то не задумывается о вашей базе данных и может произойти что угодно. Скажем сеть пропала или процесс другой запустился, или вы написали уязвимый к ошибкам код.

Кстати, есть еще один момент, на который стоит обратить внимание. Переменную экземпляра нашего класса можно создать и хранить в объекте Application и обращаться по мере необходимости, но нужно не забывать вызывать метод close(), так как постоянный коннект к базе — это тяжелый ресурс. Кроме того могут быть коллизии при работе с базой из нескольких потоков.
Но есть и другой способ, например, создавать наш объект по мере необходимости обращения к БД. Думаю это вопрос предпочтения, но который также необходимо обсудить.

А теперь самое главное. Что, если нам понадобилось использовать уже сушествующую БД с данными в приложении?
Немного погуглив, Вы сразу наткнетесь на такую «замечательную статью» — www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications в которой, как покажется, есть нужная панацея. Но не тут то было. В ней еще и ошибок несколько.

Вот они:
1) В методе createDataBase() строка:
SQLiteDatabase dbRead = getReadableDatabase();
и далее код… содержит crash приложения на НТС Desire, потому что получаем БД для чтения(она создается), но не закрывается.
Добавляем строкой ниже dbRead.close() и фикс готов, но момент спорный.
Вот что говорит дока на тему метода getReadableDatabase():
Create and/or open a database. This will be the same object returned by getWritableDatabase() unless some problem, such as a full disk, requires the database to be opened read-only. In that case, a read-only database object will be returned. If the problem is fixed, a future call to getWritableDatabase() may succeed, in which case the read-only database object will be closed and the read/write object will be returned in the future.
Like getWritableDatabase(), this method may take a long time to return, so you should not call it from the application main thread, including from ContentProvider.onCreate().

И так. Данный метод не стоит вызывать в главном потоке приложения. В остальном все понятно.
2) Ошибка: No such table android_metadata. Автор поста выкрутился, создав данную таблицу заранее в БД. Не знаю на сколько это правильный способ, но данная таблица создается в каждой sqlite-бд системой и содержит текущую локаль.
3) Ошибка: Unable to open database file. Здесь много мнений, разных мнений, которые Вы можете прочесть по ссылкам ниже.

Читайте также:  Датчик давления колес андроид

Возможно, что проблемы связаны с тем, что один поток блокирует БД и второй не может к ней обратиться, возможно проблема в правах доступа к приложению(было замечено, что чаще проблемы с БД проявляются на телефонах марки НТС именно на тех моделях, которые нельзя рутануть, хотя не только на них, например на планшетах Асер), но как бы то ни было проблемы эти есть.
Я склоняюсь к варианту, что проблема в потоках, не зря ведь нам не рекомендуют вызывать методы создания базы в главном потоке.

Возможно выходом из этого будет следующее решение(рассматривается вариант №2). Используя первый вариант работы с базой, наполнить ее данными после создания, например:

Данный подход еще нужно проверить на практике, но так как этот пост нацелен на выработку верного коллективного решения по данной тематике, то комментарии и пробы на даннную тему только приветствуются.
Мораль истории такова: если вы нашли какой-то хороший кусок кода для вашего решения, то проверьте его, не поленитесь, прежде чем копипастить в свой проект.

Вцелом, данный пост показывает(касательно способа №2) как делать не надо, но и также содержит пару любопытных мыслей.
Метод getReadableDatabase() можно переопределить например так:

Кстати: следуя практике самой платформы, поле первичного ключа стоит называть «_id».

Пишите в комментарии свои используемые практики. Мы сделаем данный пост лучше для всех, а может и мир станет чуточку добрее.

UPD Только что проверил свой подход. Все работает в эмуляторе, но будьте осторожны.

Файлик data.txt лежит в assets такой:
Zametka #1
Zametka #2
Zametka #3
Zametka #4

И класс приложения:

Отмечу, что данный класс используется только для демонстрации и проверки того, что произойдет при вызове методов getReadableDatabase()/getWritableDatabase() и создании базы. В реальных проектах код нужно адаптировать.
Кроме того в базе появилась табличка android_metadata(без моего участия), поэтому указанная выше ошибка решена.
Надеюсь кому-то пригодится.

Любопытные дополнения №1(от хабраюзера Kalobok)

Источник

База SQLite: метод по созданию таблицы не вызывается

ошибки
User-space exception detected!
java.lang.NullPointerException: Attempt to invoke virtual method ‘android.database.sqlite.SQLiteDatabase android.content.Context.openOrCreateDatabase(java.lang.Strin g, int, android.database.sqlite.SQLiteDatabase$CursorFactory, android.database.DatabaseErrorHandler)’ on a null object reference

FATAL EXCEPTION: main
java.lang.RuntimeException: java.lang.NullPointerException: Attempt to invoke virtual method ‘android.database.sqlite.SQLiteDatabase android.content.Context.openOrCreateDatabase(java.lang.Strin g, int, android.database.sqlite.SQLiteDatabase$CursorFactory, android.database.DatabaseErrorHandler)’ on a null object reference

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method ‘android.database.sqlite.SQLiteDatabase android.content.Context.openOrCreateDatabase(java.lang.Strin g, int, android.database.sqlite.SQLiteDatabase$CursorFactory, android.database.DatabaseErrorHandler)’ on a null object reference

Не работает проверка существования таблицы через метод ExecuteNonQuery() из System.Data.SQLite.dll
Использую приведенный ниже метод для определения существования таблицы в БД public int.

Почему эта функция вызывается по созданию элемента, а не по клику?
function.

Не вызывается метод
Здравствуйте! Изучаю язык C++, начал осваивать ООП. Для лучшего понимания решил написать программу.

Источник

SQLite Database Class

Definition

Some information relates to prerelease product that may be substantially modified before it’s released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

Exposes methods to manage a SQLite database.

Remarks

Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.

Constructors

A constructor used when creating managed representations of JNI objects; called by the runtime.

Читайте также:  Как включить андроид сони иксперия

Fields

When a constraint violation occurs,no ROLLBACK is executed so changes from prior commands within the same transaction are preserved.

When a constraint violation occurs, the command aborts with a return code SQLITE_CONSTRAINT.

When a constraint violation occurs, the one row that contains the constraint violation is not inserted or changed.

Use the following when no conflict action is specified.

When a UNIQUE constraint violation occurs, the pre-existing rows that are causing the constraint violation are removed prior to inserting or updating the current row.

When a constraint violation occurs, an immediate ROLLBACK occurs, thus ending the current transaction, and the command aborts with a return code of SQLITE_CONSTRAINT.

Absolute max value that can be set by #setMaxSqlCacheSize(int) .

Maximum Length Of A LIKE Or GLOB Pattern The pattern matching algorithm used in the default LIKE and GLOB implementation of SQLite can exhibit O(N^2) performance (where N is the number of characters in the pattern) for certain pathological cases.

Properties

Returns the runtime class of this Object .

(Inherited from Object) Handle

The handle to the underlying Android instance.

(Inherited from Object) IsDatabaseIntegrityOk

Runs ‘pragma integrity_check’ on the given database (and all the attached databases) and returns true if the given database (and all its attached databases) pass integrity_check, false otherwise.

Returns true if the current thread is holding an active connection to the database.

Always returns false.

Returns true if the database is currently open.

Returns true if the database is opened as read only.

Returns true if write-ahead logging has been enabled for this database.

Returns the maximum size the database may grow to.

Returns the current database page size, in bytes. -or- Sets the database page size.

Gets the path to the database file.

This API supports the Mono for Android infrastructure and is not intended to be used directly from your code.

This API supports the Mono for Android infrastructure and is not intended to be used directly from your code.

Gets the database version. -or- Sets the database version.

Methods

Acquires a reference to the object.

(Inherited from SQLiteClosable) BeginTransaction()

Begins a transaction in EXCLUSIVE mode.

Begins a transaction in IMMEDIATE mode.

Begins a transaction in EXCLUSIVE mode.

Begins a transaction in IMMEDIATE mode.

Creates and returns a copy of this object.

(Inherited from Object) Close() CompileStatement(String)

Compiles an SQL statement into a reusable pre-compiled statement object.

Create a memory backed SQLite database.

Create a memory backed SQLite database.

Convenience method for deleting rows in the database.

Deletes a database including its journal file and other auxiliary files that may have been created by the database engine.

This method disables the features enabled by #enableWriteAheadLogging() .

Dispose() (Inherited from Object) Dispose(Boolean) (Inherited from Object) EnableWriteAheadLogging()

This method enables parallel execution of queries from multiple threads on the same database.

End a transaction.

Indicates whether some other object is «equal to» this one.

(Inherited from Object) ExecPerConnectionSQL(String, Object[])

Execute the given SQL statement on all connections to this database.

Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data.

Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data.

Finds the name of the first table, which is editable.

Returns a hash code value for the object.

(Inherited from Object) Insert(String, String, ContentValues)

Convenience method for inserting a row into the database.

Convenience method for inserting a row into the database.

General method for inserting a row into the database.

Returns true if the current thread has a transaction pending.

Called by the garbage collector on an object when garbage collection determines that there are no more references to the object.

Читайте также:  Хил климб рейсинг 2 взлом андроид

(Inherited from Object) MarkTableSyncable(String, String)

Mark this table as syncable.

Mark this table as syncable.

Returns true if the new version code is greater than the current database version.

Wakes up a single thread that is waiting on this object’s monitor.

(Inherited from Object) NotifyAll()

Wakes up all threads that are waiting on this object’s monitor.

(Inherited from Object) OnAllReferencesReleased()

Called when the last reference to the object was released by a call to ReleaseReference() or Close().

Called when the last reference to the object was released by a call to #releaseReferenceFromContainer() .

(Inherited from SQLiteClosable) OpenDatabase(File, SQLiteDatabase+OpenParams)

Open the database according to the specified OpenParams parameters

Open the database according to the specified OpenParams parameters

Open the database according to the specified OpenParams parameters

Equivalent to openDatabase(file.

Equivalent to openDatabase(file.

Equivalent to openDatabase(file.

Query the given table, returning a Cursor over the result set.

Query the given table, returning a Cursor over the result set.

Query the given table, returning a Cursor over the result set.

Query the given table, returning a Cursor over the result set.

Query the given URL, returning a Cursor over the result set.

Query the given URL, returning a Cursor over the result set.

Runs the provided SQL and returns a Cursor over the result set.

Runs the provided SQL and returns a Cursor over the result set.

Runs the provided SQL and returns a cursor over the result set.

Runs the provided SQL and returns a cursor over the result set.

Attempts to release memory that SQLite holds but does not require to operate properly.

Releases a reference to the object, closing the object if the last reference was released.

(Inherited from SQLiteClosable) ReleaseReferenceFromContainer()

Releases a reference to the object that was owned by the container of the object, closing the object if the last reference was released.

(Inherited from SQLiteClosable) Replace(String, String, ContentValues)

Convenience method for replacing a row in the database.

Convenience method for replacing a row in the database.

Register a custom aggregate function that can be called from SQL expressions.

Register a custom scalar function that can be called from SQL expressions.

Sets whether foreign key constraints are enabled for the database.

Sets the Handle property.

(Inherited from Object) SetLocale(Locale)

Sets the locale for this database.

Control whether or not the SQLiteDatabase is made thread-safe by using locks around critical sections.

Sets the maximum size the database will grow to.

Sets the maximum size of the prepared-statement cache for this database.

Marks the current transaction as successful.

Returns a string representation of the object.

(Inherited from Object) UnregisterFromRuntime() (Inherited from Object) Update(String, ContentValues, String, String[])

Convenience method for updating rows in the database.

Convenience method for updating rows in the database.

Verifies that a SQL SELECT statement is valid by compiling it.

Causes the current thread to wait until another thread invokes the java.lang.Object#notify() method or the java.lang.Object#notifyAll() method for this object.

(Inherited from Object) Wait(Int64)

Causes the current thread to wait until another thread invokes the java.lang.Object#notify() method or the java.lang.Object#notifyAll() method for this object.

(Inherited from Object) Wait(Int64, Int32)

Causes the current thread to wait until another thread invokes the java.lang.Object#notify() method or the java.lang.Object#notifyAll() method for this object.

(Inherited from Object) YieldIfContended()

Temporarily end the transaction to let other threads run.

Temporarily end the transaction to let other threads run.

Temporarily end the transaction to let other threads run.

Explicit Interface Implementations

IJavaPeerable.Disposed() (Inherited from Object)
IJavaPeerable.DisposeUnlessReferenced() (Inherited from Object)
IJavaPeerable.Finalized() (Inherited from Object)
IJavaPeerable.JniManagedPeerState (Inherited from Object)
IJavaPeerable.SetJniIdentityHashCode(Int32) (Inherited from Object)
IJavaPeerable.SetJniManagedPeerState(JniManagedPeerStates) (Inherited from Object)
IJavaPeerable.SetPeerReference(JniObjectReference) (Inherited from Object)

Extension Methods

Performs an Android runtime-checked type conversion.

Источник

Оцените статью