通过内容提供者创建表或直接访问 DBHelper?其他?
Posted
技术标签:
【中文标题】通过内容提供者创建表或直接访问 DBHelper?其他?【英文标题】:Create tables via content provider or access DBHelper directly? Other? 【发布时间】:2018-10-16 13:28:56 【问题描述】:我正在构建一个 android 应用程序,该应用程序使用 DB 帮助程序类和仅用于访问 DB 的内容提供程序。我注意到,当我的应用程序启动时,它永远不会点击我的 DBHelper 类的 onCreate(),如果它们不存在的话,它具有用于表创建的所有 DDL。
我已经手动创建了一张表,并且已经确认我可以通过我的提供程序执行 CRUD 操作。我的目标是让内容提供者只访问 DBhelper 类,并让 UI 使用内容提供者进行 CRUD 操作。
我觉得我在这里缺少了部分椅子,并且可以使用一些帮助来理解这个过程应该如何工作,以便当我的应用程序启动时,系统将检查表是否存在并在它们不存在时创建。
我已将我的 DBhelper 类实现为单例,这似乎存在很多争议。
我知道我确实需要在创建操作继续之前获得一个可读或可写的数据库,至少我认为这是正确的。如果我应该通过在应用程序启动时从 MainActivity 的 onCreate 获取我的 db 类的实例来做到这一点,我遇到的问题是无法拼凑起来?或者,如果我应该在我的内容提供商中做一些事情来在应用程序启动时处理这个问题?仅供参考 - 如前所述,我确实在我的清单中注册了我的内容提供程序,在我的 MainActivity onCreate() 中,我已经成功地将我的内容提供程序用于手动构建的表上的 CRUD 操作。
非常感谢这里的任何方向。
这是我的 AppDB 类
class AppDatabase extends SQLiteOpenHelper
public static final String DATABASE_NAME = "wgutrack.db";
public static final int DATABASE_VERSION = 1;
public static final String CTINE = "CREATE TABLE IF NOT EXISTS ";
public static final String PKA = " INTEGER PRIMARY KEY AUTOINCREMENT, ";
private static final String TEXT_TYPE = " TEXT";
public static final String INTEGER_TYPE = " INTEGER";
private static final String COMMA_SEP = ", ";
private static final String NN = " NOT NULL ";
// Implement AppDatabase as a singleton
private static AppDatabase instance = null;
private AppDatabase(Context context)
super(context, DATABASE_NAME, null, DATABASE_VERSION);
/**
* Get an instance of the app's singleton db helper object
* @param context The content provider's context
* @return A SQLite DB helper object
*/
static AppDatabase getInstance(Context context)
if (instance == null)
instance = new AppDatabase(context);
return instance;
@Override
public void onCreate(SQLiteDatabase db)
// Create script for Terms table
String sqlTerms;
sqlTerms = CTINE + TermsContract.TABLE_NAME + " ("
+ TermsContract.Columns._ID + PKA
+ TermsContract.Columns.COL_TITLE + TEXT_TYPE + NN + COMMA_SEP
+ TermsContract.Columns.COL_START + INTEGER_TYPE + NN + COMMA_SEP
+ TermsContract.Columns.COL_END + INTEGER_TYPE + NN + ")";
Log.d("SQLQRY", sqlTerms);
db.execSQL(sqlTerms);
// Create script for Courses table
String sqlCourses;
sqlCourses = CTINE + CoursesContract.TABLE_NAME + " ("
+ CoursesContract.Columns._ID + PKA
+ CoursesContract.Columns.COL_TITLE + TEXT_TYPE + NN + COMMA_SEP
+ CoursesContract.Columns.COL_STATUS + TEXT_TYPE + NN + COMMA_SEP
+ CoursesContract.Columns.COL_MENTOR_ID + INTEGER_TYPE + NN + COMMA_SEP
+ CoursesContract.Columns.COL_START + INTEGER_TYPE + COMMA_SEP
+ CoursesContract.Columns.COL_END + INTEGER_TYPE + COMMA_SEP
+ CoursesContract.Columns.COL_START_NOTIFY + INTEGER_TYPE + COMMA_SEP
+ CoursesContract.Columns.COL_END_NOTIFY + INTEGER_TYPE + ")";
Log.d("SQLQRY", sqlCourses);
db.execSQL(sqlCourses);
// Create script for term / course map table
String sqlMap;
sqlMap = CTINE + TermsCourseMapContract.TABLE_NAME + " ("
+ TermsCourseMapContract.Columns._ID + PKA
+ TermsCourseMapContract.Columns.COL_TERM_ID + INTEGER_TYPE + COMMA_SEP
+ TermsCourseMapContract.Columns.COL_COURSE_ID + INTEGER_TYPE + ")";
// Create script for Mentors table
String sqlMentors;
sqlMentors = CTINE + MentorsContract.TABLE_NAME + " ("
+ MentorsContract.Columns._ID + PKA
+ MentorsContract.Columns.COL_FIRST_NAME + TEXT_TYPE + NN + COMMA_SEP
+ MentorsContract.Columns.COL_LAST_NAME + TEXT_TYPE + NN + COMMA_SEP
+ MentorsContract.Columns.COL_PHONE + TEXT_TYPE + COMMA_SEP
+ MentorsContract.Columns.COL_EMAIL + TEXT_TYPE + ")";
Log.d("SQLQRY", sqlMentors);
db.execSQL(sqlMentors);
// Create script for Assessments table
String sqlAssessments;
sqlAssessments = CTINE + AssessmentsContract.TABLE_NAME + " ("
+ AssessmentsContract.Columns._ID + PKA
+ AssessmentsContract.Columns.COL_TITLE + TEXT_TYPE + NN + COMMA_SEP
+ AssessmentsContract.Columns.COL_DESC + TEXT_TYPE + COMMA_SEP
+ AssessmentsContract.Columns.COL_TYPE + TEXT_TYPE + COMMA_SEP
+ AssessmentsContract.Columns.COL_COURSE_ID + INTEGER_TYPE + NN + ")";
Log.d("SQLQRY", sqlAssessments);
db.execSQL(sqlAssessments);
// Create script for the Notes table
String sqlNotes;
sqlNotes = CTINE + NotesContract.TABLE_NAME + " ("
+ NotesContract.Columns._ID + PKA
+ NotesContract.Columns.COL_TITLE + TEXT_TYPE + NN + COMMA_SEP
+ NotesContract.Columns.COL_TEXT + TEXT_TYPE + NN + COMMA_SEP
+ NotesContract.Columns.COL_COURSE_ID + INTEGER_TYPE + NN + ")";
Log.d("SQLQRY", sqlNotes);
db.execSQL(sqlNotes);
// Create script for the Goals table
String sqlGoals;
sqlGoals = CTINE + GoalsContract.TABLE_NAME + " ("
+ GoalsContract.Columns._ID + PKA
+ GoalsContract.Columns.COL_TITLE + TEXT_TYPE + NN + COMMA_SEP
+ GoalsContract.Columns.COL_DESC + TEXT_TYPE + NN + COMMA_SEP
+ GoalsContract.Columns.COL_DUE_DATE + INTEGER_TYPE + NN + COMMA_SEP
+ GoalsContract.Columns.COL_ASS_ID + INTEGER_TYPE + NN + ")";
Log.d("SQLQRY", sqlGoals);
db.execSQL(sqlGoals);
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
switch (oldVersion)
case 1:
// upgrade from version 1
break;
default:
throw new IllegalStateException("onUpgrade() with unknown new version: " + newVersion);
【问题讨论】:
“我的目标是让内容提供者只访问 DBhelper 类,并让 UI 使用内容提供者进行 CRUD 操作”——为什么?您是否计划让其他应用程序通过您的提供商访问此内容?如果没有,那么为什么不摆脱提供者而直接使用 SQLite(或通过 Room 或 ORM 层)?纯粹出于内部目的使用ContentProvider
并不是一种流行的方法。
【参考方案1】:
我注意到,当我的应用启动时,它并没有点击 我的 DBHelper 类的 onCreate() 具有表的所有 DDL 创作,如果它们不存在。
SQLIteOpenHelper
类的onCreate
方法在创建数据库时运行一次。它不会在每次实例化子类的实例时运行。
在开发应用程序时,更改数据库结构的最简单方法是执行以下操作之一(假设数据可能会丢失):-
从设备设置中删除/清除应用数据,然后重新运行应用。 卸载并重新安装应用程序,然后重新运行应用程序。 在onUpgrade
方法中使用合适的代码来删除表,然后调用更改后的onCreate
方法。
如果你需要保留数据,那么你可以在ALTER TABLE的限制范围内使用onUpgrade
的方法来ALTER表。
您可以通过查询 sqlite_master 表来检查表是否存在。这将返回一个有 5 列的游标,即:-
类型 table 用于表格 名称实体的名称 tbl_name 实体相关的表的名称。 根页面sql用于创建实体的 SQL
(实体与类型相关,例如表、索引、视图、触发器)
....当我的应用程序启动时,系统将检查表是否存在并且 在它们不存在时创建。
所以要检查 tablex 那么你可以使用
SELECT tbl_name FROM sqlite_master WHERE tbl_name = 'tablex' AND type = 'table';
所以你可以有一个类似于以下几行的方法:-
public boolean doesTableExist(String table_name)
boolean rv = false;
String[] columns = new String[]"sqlite_master";
String whereclause = "tbl_name=? AND type=?";
String[] whereargs = new String[]table_name,"table";
Cursor csr = yoursqlitedatabase.query("sqlite_master",columns,whereclause,wwhereargs,null,null,null);
rv = csr.getCount() > 0;
csr.close();
return rv;
如果您在 DBhelper 中包含上述内容,则 Cursor csr = yoursqlitedatabase.query("sqlite_master",columns,whereclause,wwhereargs,null,null,null);
可能是 Cursor csr = this.getWritableDatabase().query("sqlite_master",columns,whereclause,wwhereargs,null,null,null);
您通常会看到SQliteDatabase db = this.getWritabledatabase()
,然后是db.query........
然后,您可以将类似于 AppDatabase myDBHlper;
的内容作为类变量,然后在要检查的类(活动)中使用 myDBHelper = Appdatabase.getInstance(this)
和 if (myDBHelper.doestableExist("your_table")) .......
。
当然,只需使用CREATE TABLE IF NOT EXISTS ......
就足够了。
您可以通过覆盖作为 SQLiteOpenHelper(又名 DBHelper)子类的类的 onOpen
方法或 onConfigure
方法来实现检查等。
【讨论】:
以上是关于通过内容提供者创建表或直接访问 DBHelper?其他?的主要内容,如果未能解决你的问题,请参考以下文章