android - 通过内容提供者创建表或直接访问 DBHelper?其他?
问题描述
我正在构建一个 Android 应用程序,该应用程序使用数据库帮助程序类和仅用于访问数据库的内容提供程序。我注意到,当我的应用程序启动时,它永远不会点击我的 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 类的 onCreate(),如果它们不存在的话,它具有用于表创建的所有 DDL。
类的onCreate
方法在SQLIteOpenHelper
创建数据库时运行一次。它不会在每次实例化子类的实例时运行。
在开发应用程序时,更改数据库结构的最简单方法是执行以下操作之一(假设数据可能会丢失):-
- 从设备上的设置中删除/清除应用程序的数据并重新运行应用程序。
- 卸载并重新安装应用程序,然后重新运行应用程序。
- 在删除表的方法中使用合适的代码,
onUpgrade
然后调用更改的onCreate
方法。
如果您需要保留数据,那么您可以在ALTER TABLEonUpgrade
的限制范围内使用 ALTER 表的方法。
您可以通过查询sqlite_master表来检查表是否存在。这将返回一个有 5 列的游标,即:-
- 类型
- 一桌一桌
- 命名实体的名称
- 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 ......
就足够了。
您可以通过覆盖作为onOpen
SQLiteOpenHelper(又名 DBHelper)子类的类的方法或该onConfigure
方法来实现检查等。
推荐阅读
- r - 错误:无法在未命名的向量中选择
- azure-cosmosdb - 在 cosmosDB/MongoDB API 中,使用排序规则选项 numericOrdering 按包含数字的字符串字段进行排序不起作用
- python - TypeError:“PosixPath”类型的参数不可迭代,旧解决方案不起作用
- c# - 为什么我不能全部删除?
- r - 将数字转换为字符串,同时在 R 中保持字符不变
- devops - 持续部署是否意味着我们不使用预生产环境?
- python - 如何在 Json 响应 Python 中合并 order_id
- amazon-s3 - 如何使用 Cloudfront 在没有公共访问权限的私有 S3 存储桶上托管静态网站?
- react-native - React Native:_this.setState 不是 react-navigation 应用程序中抛出的函数
- python - openCV中是否有一种方法可以裁剪图像并将未裁剪的区域保留为黑色?