Android的SQLiteOpenHelper类 笔记241027

SQLiteOpenHelper

SQLiteOpenHelper是Android开发中用于管理SQLite数据库的一个非常重要的工具类。以下是对SQLiteOpenHelper的详细介绍:

一、基本概念

SQLiteOpenHelper是一个抽象类,它主要用于管理数据库的创建和版本管理。通过继承这个类,开发者可以重写一些方法以实现数据库的创建、升级和降级等功能。

二、主要方法

  1. 构造方法:用于创建SQLiteOpenHelper对象,需要传入数据库名称、版本号和一个可选的CursorFactory对象。
    public SQLiteOpenHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version)
    public SQLiteOpenHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version, @Nullable DatabaseErrorHandler errorHandler)
    public SQLiteOpenHelper(@Nullable Context context, @Nullable String name, int version, @NonNull SQLiteDatabase.OpenParams openParams)
  2. onCreate(SQLiteDatabase db):在数据库第一次创建时调用,用于执行创建表和初始化数据等操作。
  3. onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):在数据库版本升级时调用,用于执行表结构的修改、数据迁移等操作。
  4. onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion):在数据库版本降级时调用,但这个方法不是必须的,因为在实际开发中降级操作并不常见。
  5. getReadableDatabase():获取一个可读的数据库对象。如果数据库不存在,则会先调用onCreate()方法创建数据库。
  6. getWritableDatabase():获取一个可写的数据库对象。如果数据库不存在,也会先调用onCreate()方法创建数据库。



SQLiteOpenHelper的主要方法

方法名

作用

备注

SQLiteOpenHelper(
构造方法三个
创建SQLiteOpenHelper实例一般用 new SQLiteOpenHelper(Context context, String databaseName, CursorFactory factory, int version)
参数1可填MianActivity的实例,如this或MainActivity.this
参数2是数据库名称,如果不存在就会调用onCreate()方法
参数3指定CursorFactory , 可以为null(使用默认的CursorFactory)
参数4是版本号,如果变动就会执行onUpgrade()方法

抽象方法
onCreate()

创建数据库时做什么,
可以写入创建表结构的sql语句

没有对应的数据库时才调用
(构造函数的参数中的数据库名对应的数据库不存在时才调用)
构造获得实例,实例调用getReadableDatabase()
getWritableDatabase()时,发现构造时指定的数据库不存在,就会调用该方法

抽象方法
onUpgrade()

升级数据库版本时做什么

构造方法参数的版本号上升时才调用

非抽象,可选
onDowngrade()
降级数据库版本时做什么构造方法参数的版本号下降时才调用
非抽象,可选
onOpen()
打开数据库时做什么

close()

关闭所有打开的数据库对象

getWritableDatabase()

创建或打开可以读/写的数据库

通过返回的SQLiteDatabase对象对数据库进行操作

getReadableDatabase()

创建或打开可读的数据库

同上

SQLiteDatabase的主要方法

方法名

作用

备注

execSQL()

可进行增删改操作, 不能进行查询操作

query()、rawQuery()

查询数据库

insert()

插入数据

delete()

删除数据

SQLiteOpenHelper的构造方法

SQLiteOpenHelper 的构造方法通常看起来像这样(基于 Android SDK 的源代码):

public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version, DatabaseErrorHandler errorHandler) {// 验证版本号是否有效if (version < 1) {throw new IllegalArgumentException("Version must be >= 1, was " + version);}// 保存传入的参数mContext = context;mName = name;mFactory = factory;mNewVersion = version;mErrorHandler = errorHandler;
}// 还有一个更简单的构造方法,它不接受 DatabaseErrorHandler
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {this(context, name, factory, version, null);
}

在上面的构造方法中:

  • context 是一个 Context 对象,它允许访问应用的资源和类,以及调用应用级操作,如启动活动、广播和接收意图等。
  • name 是数据库文件的名称。如果不包括路径,则数据库文件将被存储在应用的私有文件目录中。
  • factory 是一个用于创建游标对象的 CursorFactory。如果传入 null,则使用默认的游标工厂。
  • version 是数据库的版本号。这是一个整数,用于跟踪数据库的结构变化。当版本号增加时,onUpgrade 方法将被调用。
  • errorHandler 是一个 DatabaseErrorHandler 对象,它允许在数据库遇到错误时执行自定义的错误处理逻辑。如果传入 null,则使用默认的错误处理器。

在创建 SQLiteOpenHelper 的子类时,我们需要调用其中一个构造方法来初始化父类。然后,我们可以实现 onCreateonUpgrade 等方法来定义数据库的结构和升级逻辑。

例如:

public class MyDatabaseHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "mydatabase.db";private static final int DATABASE_VERSION = 1;public MyDatabaseHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}@Overridepublic void onCreate(SQLiteDatabase db) {// 创建表的 SQL 语句String CREATE_TABLE = "CREATE TABLE mytable (" +"id INTEGER PRIMARY KEY AUTOINCREMENT," +"name TEXT" +");";db.execSQL(CREATE_TABLE);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// 版本升级时的逻辑db.execSQL("DROP TABLE IF EXISTS mytable");onCreate(db);}
}

在这个例子中,我们创建了一个名为 MyDatabaseHelper 的类,它继承自 SQLiteOpenHelper。我们在构造方法中调用了父类的构造方法,并传入了数据库名称、版本号和上下文对象。然后,我们实现了 onCreateonUpgrade 方法来定义数据库的结构和升级逻辑。

三、 SQLiteOpenHelper源代码

以下是一个简化的 SQLiteOpenHelper 源代码示例,并附有关键部分的解释:

package android.database.sqlite;import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;public abstract class SQLiteOpenHelper {// 调试标志,用于确定是否严格只读private static final boolean DEBUG_STRICT_READONLY = false;// 上下文对象,用于访问应用的资源和类private final Context mContext;// 数据库文件名private final String mName;// 用于创建游标对象的工厂,如果为 null,则使用默认工厂private final CursorFactory mFactory;// 数据库版本号private final int mNewVersion;// 数据库错误处理器,如果为 null,则使用默认处理器private final DatabaseErrorHandler mErrorHandler;// 数据库对象,可能为 nullprivate SQLiteDatabase mDatabase;// 标记数据库是否正在初始化private boolean mIsInitializing;// SQLiteOpenHelper 的构造函数public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version, DatabaseErrorHandler errorHandler) {if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);mContext = context;mName = name;mFactory = factory;mNewVersion = version;mErrorHandler = errorHandler;}// 简化构造函数,不指定错误处理器public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {this(context, name, factory, version, null);}// 创建或打开一个数据库,用于读写。如果数据库磁盘空间已满,则尝试以只读方式打开public synchronized SQLiteDatabase getWritableDatabase() {// ...(实现细节省略)}// 创建或打开一个数据库,用于读取。如果数据库磁盘空间已满,则只能以只读方式打开public synchronized SQLiteDatabase getReadableDatabase() {// ...(实现细节省略)}// 当数据库第一次创建时调用此方法public abstract void onCreate(SQLiteDatabase db);// 当数据库版本升级时调用此方法public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);// 当数据库版本降级时调用此方法(可选实现)public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {throw new SQLiteException("Can't downgrade database from version " + oldVersion + " to " + newVersion);}// 当数据库打开时调用此方法(可选实现)public void onOpen(SQLiteDatabase db) {}// ...(其他方法和内部类省略)
}
关键部分解释:
  1. 构造函数SQLiteOpenHelper 提供了两个构造函数,允许开发者指定数据库名称、版本号、游标工厂和错误处理器。版本号必须大于等于 1。
  2. getWritableDatabase():此方法用于创建或打开一个数据库,用于读写操作。如果数据库磁盘空间已满,则尝试以只读方式打开,但会抛出异常。
  3. getReadableDatabase():此方法用于创建或打开一个数据库,用于读取操作。如果数据库磁盘空间已满,则只能以只读方式打开。
  4. onCreate(SQLiteDatabase db):这是一个抽象方法,当数据库第一次创建时调用。开发者应在此方法中编写创建表和初始化数据的 SQL 语句。
  5. onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):这也是一个抽象方法,当数据库版本升级时调用。开发者应在此方法中编写升级数据库的 SQL 语句,如添加新列、修改表结构等。
  6. onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion):这是一个可选实现的方法,当数据库版本降级时调用。默认情况下,此方法会抛出异常,因为降级操作通常不被推荐。
  7. onOpen(SQLiteDatabase db):这是一个可选实现的方法,当数据库打开时调用。开发者可以在此方法中执行一些初始化操作。

请注意,上述代码是一个简化的示例,并省略了部分实现细节和内部类。在实际开发中,SQLiteOpenHelper 的实现可能会更加复杂,具体取决于应用的需求和数据库的结构。




用法实例

一个用 匿名内部类实例化SQLiteOpenHelper的Activity

package com.example.emptyviewsactivity2410261826;import android.annotation.SuppressLint;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatEditText;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;public class MainActivity extends AppCompatActivity {final String DbName = "note1", TbName = "tableA1" , Col0="id" , Col1="content";final int RowQuantity = 666;LinearLayout linearLayout = null;TableLayout tableLayout = null;final TableRow[] TableRows = new TableRow[RowQuantity];final TextView[] TvAr = new TextView[RowQuantity];final EditText[] EtAr = new EditText[RowQuantity];
//    final AppCompatEditText EtAr[] = new AppCompatEditText[RowQuantity];final Button[] CopyBtnAr = new Button[RowQuantity];final Button[] PasteBtnAr = new Button[RowQuantity];final Button[] CutBtnAr = new Button[RowQuantity];final Button[] DelBtnAr = new Button[RowQuantity];SQLiteOpenHelper sqliteOpenHelper;SQLiteDatabase sqliteDatabase;@SuppressLint("MissingInflatedId")@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); Log.i("onCreate()","onCreate()");EdgeToEdge.enable(this);setContentView(R.layout.activity_main);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});/// 👆上面部分是新建项目自动生成的linearLayout = findViewById(R.id.LinearLayoutA1);tableLayout = findViewById(R.id.tableLayoutA1);//        EditText editText = new EditText(this);  linearLayout.addView(editText);
//
//        AppCompatEditText appCompatEditText = new AppCompatEditText(MainActivity.this); linearLayout.addView(appCompatEditText);
//
//        AutoCompleteTextView autoCompleteTextView = new AutoCompleteTextView(this); linearLayout.addView(autoCompleteTextView);
//
//        MultiAutoCompleteTextView multiAutoCompleteTextView = new MultiAutoCompleteTextView(MainActivity.this); linearLayout.addView(multiAutoCompleteTextView);/*删除数据库deleteDatabase(DbName)删除数据库, Activity,AppCompatActivity都自带删除Sqlite数据库的方法, 这是实现自最顶层 public abstract class Context 的抽象方法  public abstract boolean deleteDatabase(String name);AppCompatActivity extends FragmentActivity extends ComponentActivity extends androidx.core.app.ComponentActivity extends Activity extends ContextThemeWrapper extends ContextWrapper extends Context*/
//        deleteDatabase(DbName);/*通过匿名内部类实现SQLiteOpenHelper, 也可用继承类实现.实例化SQLiteOpenHelper时虽然指定了数据库名称和版本,但还不会创建或打开数据库,直到实例执行 getReadableDatabase() 或 getWritableDatabase() 获取数据库时时,才会打开 或 创建再打开 数据库*/sqliteOpenHelper = new SQLiteOpenHelper(MainActivity.this, DbName, null, 1) {//必须//onCreate(SQLiteDatabase sqLiteDatabase数据库实例)///在执行 getReadableDatabase() 或 getWritableDatabase() 获取数据库时时, 如果数据库名称对应的数据库不存在,就会调用该方法,该方法为abstract抽象方法,必须实现.@Overridepublic void onCreate(SQLiteDatabase sqLiteDatabase) {System.out.println("SQLiteOpenHelper 的 onCreate(SQLiteDatabase sqLiteDatabase)被调用    //在执行 getReadableDatabase() 或 getWritableDatabase() 获取数据库时时, 如果数据库名称对应的数据库不存在,就会调用该方法,该方法为abstract抽象方法,必须实现");final String CreateTableSql = "CREATE TABLE "+TbName+" ( id INTEGER PRIMARY KEY , content TEXT )";sqLiteDatabase.execSQL(CreateTableSql);for(int r=0; r<RowQuantity; r++){ContentValues cvs = new ContentValues(2);cvs.put(Col0, r);cvs.put(Col1, "");sqLiteDatabase.insert(TbName, null, cvs);}}//必须//onUpgrade(SQLiteDatabase sqLiteDatabase数据库实例, int oldVersion旧版本号, int newVersion新版本号)///在执行 getReadableDatabase() 或 getWritableDatabase() 获取数据库时时, 如果数据库版本号升高,就会调用该方法,该方法为abstract抽象方法,必须实现.    在创建数据库时不会调用该方法@Overridepublic void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {System.out.println("SQLiteOpenHelper 的 onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion)被调用    //在执行 getReadableDatabase() 或 getWritableDatabase() 获取数据库时时, 如果数据库版本号升高,就会调用该方法,该方法为abstract抽象方法,必须实现.    在创建数据库时不会调用该方法");}//非抽象,可选//onDowngrade(SQLiteDatabase sqLiteDatabase数据库实例, int oldVersion旧版本号, int newVersion新版本号)///在执行 getReadableDatabase() 或 getWritableDatabase() 获取数据库时时, 如果数据库版本号发生变动,就会调用该方法,该方法非抽象,可选.    在创建数据库时不会调用该方法@Overridepublic void onDowngrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {System.out.println("SQLiteOpenHelper 的 onDowngrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion)被调用    //在执行 getReadableDatabase() 或 getWritableDatabase() 获取数据库时时, 如果数据库版本号降低,就会调用该方法,该方法非抽象,可选.    在创建数据库时不会调用该方法");}//非抽象,可选//onOpen(SQLiteDatabase sqLiteDatabase数据库实例)//在执行 getReadableDatabase() 或 getWritableDatabase() 获取数据库时时, 被调用@Overridepublic void onOpen(SQLiteDatabase sqLiteDatabase) {Log.i("onOpen(SQLiteDatabase sqLiteDatabase)","SQLiteOpenHelper 的 onOpen(SQLiteDatabase sqLiteDatabase)被调用    //在执行 getReadableDatabase() 或 getWritableDatabase() 获取数据库时时, 会调用onOpen(SQLiteDatabase db)方法");@SuppressLint("Recycle") Cursor cursor = sqLiteDatabase.rawQuery("SELECT COUNT(*) FROM "+TbName, null);cursor.moveToFirst(); if(cursor.getInt(0) != RowQuantity){ Log.i("库表均已存在,但行数不对应","库表均已存在,但行数不对应, 将 DELETE TABLE FROM table-name 然后重新 INSERT INTO");sqLiteDatabase.delete(TbName,null,null);for(int r=0; r<RowQuantity; r++){sqLiteDatabase.execSQL("INSERT INTO " + TbName + " VALUES (?,?) " , new Object[]{r,""});}}}};sqliteDatabase = sqliteOpenHelper.getWritableDatabase();@SuppressLint("Recycle") Cursor cursor = sqliteDatabase.rawQuery("SELECT * FROM "+TbName, null);for(int r=0; cursor.moveToNext(); r++){TableRow row = TableRows[r] = new TableRow(this); tableLayout.addView(row);TextView tv = TvAr[r] = new TextView(this); row.addView(tv); tv.setText(cursor.getString(0));EditText et = EtAr[r] = new EditText(this); row.addView(et); et.setText(cursor.getString(1));Button copyBtn = CopyBtnAr[r] = new Button(this); row.addView(copyBtn, 100, 100); copyBtn.setText("复");copyBtn.setOnClickListener((view)->{ClipboardManager clipboardManager = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);ClipData clipData = ClipData.newPlainText("text", et.getEditableText().toString());clipboardManager.setPrimaryClip(clipData);});Button pBtn = PasteBtnAr[r] = new Button(this); row.addView(pBtn, 100, 100); pBtn.setText("粘"); pBtn.setOnClickListener((view)->{ et.setText(((ClipboardManager)getSystemService(CLIPBOARD_SERVICE)).getPrimaryClip().getItemAt(0).getText()); });Button cutBtn = CutBtnAr[r] = new Button(this); row.addView(cutBtn, 100, 100); cutBtn.setText("剪"); cutBtn.setOnClickListener((view)->{copyBtn.callOnClick(); et.setText("");});Button dBtn = DelBtnAr[r] = new Button(this); row.addView(dBtn, 100, 100); dBtn.setText("删"); dBtn.setOnClickListener((view)->{ et.setText(""); });}//       for(int r=0; r<RowQuantity; r++){
//           TableRow row = tableRows[r] = new TableRow(this); tableLayout.addView(row);
//           EditText et = etAr[r] = new EditText(this); row.addView(et);
//
//       }/*测试多次调用  getReadableDatabase() 和 getWritableDatabase() 获取SQLiteDatabase数据库实例多次调用  getReadableDatabase() 和 getWritableDatabase() 返回同一个SQLiteDatabase实例*/SQLiteDatabase dbw , dbr;dbr = sqliteOpenHelper.getReadableDatabase();Log.i("dbw.isReadOnly()",""+dbr.isReadOnly());dbw = sqliteOpenHelper.getWritableDatabase();Log.i("dbw.isReadOnly()",""+dbw.isReadOnly());
//        dbr = sqliteOpenHelper.getReadableDatabase();System.out.println("dbw==dbr 结果 "+(dbw==dbr));Log.i("dbw.isReadOnly()",""+dbw.isReadOnly());/*删除数据库deleteDatabase(DbName)删除数据库, Activity,AppCompatActivity都自带删除Sqlite数据库的方法, 这是实现自最顶层 public abstract class Context 的抽象方法  public abstract boolean deleteDatabase(String name);AppCompatActivity extends FragmentActivity extends ComponentActivity extends androidx.core.app.ComponentActivity extends Activity extends ContextThemeWrapper extends ContextWrapper extends Context*/
//        deleteDatabase(DbName);}void save(){for(int r=0; r<RowQuantity; r++){ContentValues cvs = new ContentValues();cvs.put(Col1, EtAr[r].getText().toString());sqliteDatabase.update(TbName, cvs, "id=?", new String[]{""+r});}}@Overrideprotected void onStart() {super.onStart(); Log.i("onStart()","onStart()");}@Overrideprotected void onPause() {super.onPause(); Log.i(" onPause()"," onPause()");save();}@Overrideprotected void onStop() {super.onStop(); Log.i("onStop()","onStop()");save();}@Overrideprotected void onRestart() {super.onRestart(); Log.i("onRestart()","onRestart()");}@Overrideprotected void onPostResume() {super.onPostResume(); Log.i("onPostResume()","onPostResume()");}@Overrideprotected void onDestroy() {super.onDestroy(); Log.i("onDestroy()","onDestroy()");save();}}










一些用法收集参考

public class SQLiteHelper extends SQLiteOpenHelper {private SQLiteDatabase sqLiteDatabase;//调用父类 SQLiteOpenHelper 的构造函数public SQLiteHelper(Context context) {//context上下文环境(例如,一个 Activity),数据库名字,一个可选的游标工厂(通常是 Null),一个代表你正在使用的数据库模型版本的整数。super(context, DBUtils.DATABASE_NAME, null, DBUtils.DATABASE_VERSION);sqLiteDatabase = this.getWritableDatabase();}//创建数据库 只在没有数据库时执行@Overridepublic void onCreate(SQLiteDatabase db) {//execSQL() 方法适用于所有不返回结果的 SQL 语句db.execSQL("CREATE TABLE " + DBUtils.DATABASE_TABLE + "(" + DBUtils.NOTE_ID +" INTEGER PRIMARY KEY AUTOINCREMENT," + DBUtils.NOTE_CONTENT +" TEXT," + DBUtils.NOTE_TIME + " TEXT)");}//把一个数据库从旧的模型转变到新的模型。//它需要三个参数,一个 SQLiteDatabase 对象,一个旧的版本号和一个新的版本号@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}//添加数据public boolean insertData(String userContent, String userTime) {//ContentValues 储存数据,只能存储基本类型的数据,不能存储对象ContentValues values = new ContentValues();values.put(DBUtils.NOTE_CONTENT, userContent);values.put(DBUtils.NOTE_TIME, userTime);//插入数据//第一个参数是表的名称//第二个参数为空值字段,就是如果第三个参数为空(null)的时候就会用到第二个参数的值。用第二个参数代替第三个参数组拼成SQL语句//比如:insert into person(name) values(null)   这里的person字段使用了第二个参数的name//第三个参数不为空就不会用到第二个参数return sqLiteDatabase.insert(DBUtils.DATABASE_TABLE, null, values) > 0;}//删除数据public boolean deleteData(String id) {String sql = DBUtils.NOTE_ID + "=?";String[] contentValuesArrary = new String[]{String.valueOf(id)};//1表名、2字段名、3占位符的数据return sqLiteDatabase.delete(DBUtils.DATABASE_TABLE, sql, contentValuesArrary) > 0;}//修改数据public boolean updateData(String id, String content, String userYear) {ContentValues contentValues = new ContentValues();contentValues.put(DBUtils.NOTE_CONTENT, content);contentValues.put(DBUtils.NOTE_TIME, userYear);String sql = DBUtils.NOTE_ID + "=?";String[] strings = new String[]{id};//1表名、2需要更新值、3以什么条件字段更新、4条件字段的数据值(占位符的值)return sqLiteDatabase.update(DBUtils.DATABASE_TABLE, contentValues, sql, strings) > 0;}//查询数据public List<NotepadBean> qurry() {List<NotepadBean> list = new ArrayList<NotepadBean>();//1 表名、   2 需要查询的字段列表,用字符串数组形式传入,null为所有的字段、   3 以什么条件字段查询、   4 条件字段的数据值(占位符的值)、// 5 groupBy相当于select语句的groupby后面的部分、   6 having相当于select语句的having后面的部分、  7 order是我们想要的排序方式。Cursor cursor = sqLiteDatabase.query(DBUtils.DATABASE_TABLE, null, null, null,null, null, DBUtils.NOTE_ID + " desc");if (cursor != null) {while (cursor.moveToNext()) {NotepadBean noteInfo = new NotepadBean();String id = String.valueOf(cursor.getInt(cursor.getColumnIndex(DBUtils.NOTE_ID)));String content = cursor.getString(cursor.getColumnIndex(DBUtils.NOTE_CONTENT));String time = cursor.getString(cursor.getColumnIndex(DBUtils.NOTE_TIME));noteInfo.setId(id);noteInfo.setNotepadContent(content);noteInfo.setNotepadTime(time);list.add(noteInfo);}cursor.close();}return list;}
}
package com.example.dbproject;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
public class DbContect extends SQLiteOpenHelper {private static final int VERSION=1;private static final String DBNAME="Users.db";   //  创建数据库名叫 Usersprivate Context mContext;public DbContect(Context context){super(context,DBNAME,null,VERSION);mContext = context;}//创建数据库 只在没有数据库时执行public void onCreate(SQLiteDatabase db){//创建密码表  pwd_tbdb.execSQL("create table pwd_tb (pwd varchar(20) primary key)");//创建收入表    user_tbdb.execSQL("create table user_tb(_id integer primary key autoincrement, money decimal," +" time varchar(10),type varchar(10),handler varchar(100),mark varchar(200))");}//数据库版本更新时执行public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){db.execSQL("drop table if exists pwd_tb");db.execSQL("drop table if exists user_tb");onCreate(db);}}




SQLiteOpenHelper是Android开发中用于管理SQLite数据库的一个非常重要的工具类。以下是对SQLiteOpenHelper的详细介绍:

一、基本概念

SQLiteOpenHelper是一个抽象类,它主要用于管理数据库的创建和版本管理。通过继承这个类,开发者可以重写一些方法以实现数据库的创建、升级和降级等功能。

二、主要方法

  1. 构造方法:用于创建SQLiteOpenHelper对象,需要传入数据库名称、版本号和一个可选的CursorFactory对象。
  2. onCreate(SQLiteDatabase db):在数据库第一次创建时调用,用于执行创建表和初始化数据等操作。
  3. onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):在数据库版本升级时调用,用于执行表结构的修改、数据迁移等操作。
  4. onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion):在数据库版本降级时调用,但这个方法不是必须的,因为在实际开发中降级操作并不常见。
  5. getReadableDatabase():获取一个可读的数据库对象。如果数据库不存在,则会先调用onCreate()方法创建数据库。
  6. getWritableDatabase():获取一个可写的数据库对象。如果数据库不存在,也会先调用onCreate()方法创建数据库。

三、使用示例

以下是一个使用SQLiteOpenHelper创建数据库、表以及进行增删改查操作的简单示例:

  1. 创建数据库帮助类
public class MyDatabaseHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "mydatabase.db";private static final int DATABASE_VERSION = 1;public MyDatabaseHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}@Overridepublic void onCreate(SQLiteDatabase db) {String createTable = "CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)";db.execSQL(createTable);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {db.execSQL("DROP TABLE IF EXISTS users");onCreate(db);}
}
  1. 使用数据库帮助类进行增删改查操作
MyDatabaseHelper dbHelper = new MyDatabaseHelper(context);
SQLiteDatabase db = dbHelper.getWritableDatabase();// 插入数据
ContentValues values = new ContentValues();
values.put("name", "John Doe");
long id = db.insert("users", null, values);// 查询数据
Cursor cursor = db.query("users", null, null, null, null, null, null);
while (cursor.moveToNext()) {int userId = cursor.getInt(cursor.getColumnIndex("id"));String userName = cursor.getString(cursor.getColumnIndex("name"));// 处理查询到的数据
}
cursor.close();// 更新数据
ContentValues updateValues = new ContentValues();
updateValues.put("name", "Jane Smith");
db.update("users", updateValues, "id=?", new String[]{String.valueOf(id)});// 删除数据
db.delete("users", "id=?", new String[]{String.valueOf(id)});// 关闭数据库
db.close();

四、注意事项

  1. 数据库版本管理:在开发过程中,随着应用程序的更新,数据库结构可能会发生变化。因此,合理使用onUpgrade()方法来进行数据库结构的升级是非常重要的。
  2. 异常处理:在进行数据库操作时,可能会遇到各种异常情况,如SQL语法错误、数据库文件损坏等。因此,在实际开发中,应该添加适当的异常处理代码来确保程序的健壮性。
  3. 性能优化:对于大规模的数据库操作,如批量插入、更新或删除数据,应该考虑使用事务(Transaction)来提高性能并减少数据库锁定的时间。

综上所述,SQLiteOpenHelper是Android开发中管理SQLite数据库的重要工具类。通过合理使用该类,开发者可以实现高效的数据管理,从而提升应用程序的性能和用户体验。







如何使用SQLiteOpenHelper

SQLiteOpenHelper 是 Android 平台上用于管理 SQLite 数据库的一个辅助类。它简化了数据库的创建和版本管理。以下是使用 SQLiteOpenHelper 的基本步骤:

1. 创建一个继承自 SQLiteOpenHelper 的类

首先,你需要创建一个类,这个类继承自 SQLiteOpenHelper 并实现其两个抽象方法:onCreate(SQLiteDatabase db)onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;public class MyDatabaseHelper extends SQLiteOpenHelper {// 数据库名称private static final String DATABASE_NAME = "my_database.db";// 数据库版本private static final int DATABASE_VERSION = 1;// 创建一个表private static final String TABLE_CREATE ="CREATE TABLE my_table (" +"id INTEGER PRIMARY KEY AUTOINCREMENT, " +"name TEXT NOT NULL, " +"age INTEGER NOT NULL);";public MyDatabaseHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL(TABLE_CREATE);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// 如果表已经存在,删除表db.execSQL("DROP TABLE IF EXISTS my_table");// 重新创建表onCreate(db);}
}

2. 在你的 Activity 或其他组件中使用 SQLiteOpenHelper

在你的 Activity 或其他组件中,你可以通过实例化 MyDatabaseHelper 类来获取 SQLiteDatabase 对象,然后执行 CRUD(创建、读取、更新、删除)操作。

import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.Toast;public class MainActivity extends AppCompatActivity {private MyDatabaseHelper dbHelper;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);dbHelper = new MyDatabaseHelper(this);// 插入数据insertData();// 查询数据queryData();}private void insertData() {SQLiteDatabase db = dbHelper.getWritableDatabase();ContentValues values = new ContentValues();values.put("name", "Alice");values.put("age", 30);long newRowId = db.insert("my_table", null, values);Toast.makeText(this, "Inserted Row ID: " + newRowId, Toast.LENGTH_SHORT).show();}private void queryData() {SQLiteDatabase db = dbHelper.getReadableDatabase();String[] projection = {"id","name","age"};Cursor cursor = db.query("my_table",   // 表名projection,   // 要返回的列null,         // WHERE 子句的选择条件null,         // WHERE 子句的选择参数null,         // GROUP BY 子句null,         // HAVING 子句null          // ORDER BY 子句);while (cursor.moveToNext()) {int id = cursor.getInt(cursor.getColumnIndexOrThrow("id"));String name = cursor.getString(cursor.getColumnIndexOrThrow("name"));int age = cursor.getInt(cursor.getColumnIndexOrThrow("age"));// 处理查询结果Toast.makeText(this, "ID: " + id + ", Name: " + name + ", Age: " + age, Toast.LENGTH_SHORT).show();}cursor.close();}
}

3. 注意事项

  • 线程安全:SQLite 数据库不是线程安全的,因此你应该确保所有的数据库操作都在一个单独的线程中执行,或者使用 AsyncTask 或其他异步方法。
  • 关闭游标:每次使用完 Cursor 后,都应该调用 cursor.close() 方法来释放资源。
  • 错误处理:在实际应用中,你应该添加适当的错误处理逻辑,比如捕获 SQLException

通过以上步骤,你就可以在 Android 应用中使用 SQLiteOpenHelper 来管理 SQLite 数据库了。

























Android API34 的 SQLiteOpenHelper 的源码

/** Copyright (C) 2007 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package android.database.sqlite;import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.os.FileUtils;
import android.util.Log;import java.io.File;
import java.util.Objects;/*** A helper class to manage database creation and version management.** <p>You create a subclass implementing {@link #onCreate}, {@link #onUpgrade} and* optionally {@link #onOpen}, and this class takes care of opening the database* if it exists, creating it if it does not, and upgrading it as necessary.* Transactions are used to make sure the database is always in a sensible state.** <p>This class makes it easy for {@link android.content.ContentProvider}* implementations to defer opening and upgrading the database until first use,* to avoid blocking application startup with long-running database upgrades.** <p>For an example, see the NotePadProvider class in the NotePad sample application,* in the <em>samples/</em> directory of the SDK.</p>** <p class="note"><strong>Note:</strong> this class assumes* monotonically increasing version numbers for upgrades.</p>** <p class="note"><strong>Note:</strong> the {@link AutoCloseable} interface was* first added in the {@link android.os.Build.VERSION_CODES#Q} release.</p>*/
public abstract class SQLiteOpenHelper implements AutoCloseable {private static final String TAG = SQLiteOpenHelper.class.getSimpleName();private final Context mContext;@UnsupportedAppUsageprivate final String mName;private final int mNewVersion;private final int mMinimumSupportedVersion;private SQLiteDatabase mDatabase;private boolean mIsInitializing;private SQLiteDatabase.OpenParams.Builder mOpenParamsBuilder;/*** Create a helper object to create, open, and/or manage a database.* This method always returns very quickly.  The database is not actually* created or opened until one of {@link #getWritableDatabase} or* {@link #getReadableDatabase} is called.** @param context to use for locating paths to the the database* @param name of the database file, or null for an in-memory database* @param factory to use for creating cursor objects, or null for the default* @param version number of the database (starting at 1); if the database is older,*     {@link #onUpgrade} will be used to upgrade the database; if the database is*     newer, {@link #onDowngrade} will be used to downgrade the database*/public SQLiteOpenHelper(@Nullable Context context, @Nullable String name,@Nullable CursorFactory factory, int version) {this(context, name, factory, version, null);}/*** Create a helper object to create, open, and/or manage a database.* The database is not actually created or opened until one of* {@link #getWritableDatabase} or {@link #getReadableDatabase} is called.** <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be* used to handle corruption when sqlite reports database corruption.</p>** @param context to use for locating paths to the the database* @param name of the database file, or null for an in-memory database* @param factory to use for creating cursor objects, or null for the default* @param version number of the database (starting at 1); if the database is older,*     {@link #onUpgrade} will be used to upgrade the database; if the database is*     newer, {@link #onDowngrade} will be used to downgrade the database* @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database* corruption, or null to use the default error handler.*/public SQLiteOpenHelper(@Nullable Context context, @Nullable String name,@Nullable CursorFactory factory, int version,@Nullable DatabaseErrorHandler errorHandler) {this(context, name, factory, version, 0, errorHandler);}/*** Create a helper object to create, open, and/or manage a database.* This method always returns very quickly.  The database is not actually* created or opened until one of {@link #getWritableDatabase} or* {@link #getReadableDatabase} is called.** @param context to use for locating paths to the the database* @param name of the database file, or null for an in-memory database* @param version number of the database (starting at 1); if the database is older,*     {@link #onUpgrade} will be used to upgrade the database; if the database is*     newer, {@link #onDowngrade} will be used to downgrade the database* @param openParams configuration parameters that are used for opening {@link SQLiteDatabase}.*        Please note that {@link SQLiteDatabase#CREATE_IF_NECESSARY} flag will always be*        set when the helper opens the database*/public SQLiteOpenHelper(@Nullable Context context, @Nullable String name, int version,@NonNull SQLiteDatabase.OpenParams openParams) {this(context, name, version, 0, openParams.toBuilder());}/*** Same as {@link #SQLiteOpenHelper(Context, String, CursorFactory, int, DatabaseErrorHandler)}* but also accepts an integer minimumSupportedVersion as a convenience for upgrading very old* versions of this database that are no longer supported. If a database with older version that* minimumSupportedVersion is found, it is simply deleted and a new database is created with the* given name and version** @param context to use for locating paths to the the database* @param name the name of the database file, null for a temporary in-memory database* @param factory to use for creating cursor objects, null for default* @param version the required version of the database* @param minimumSupportedVersion the minimum version that is supported to be upgraded to*            {@code version} via {@link #onUpgrade}. If the current database version is lower*            than this, database is simply deleted and recreated with the version passed in*            {@code version}. {@link #onBeforeDelete} is called before deleting the database*            when this happens. This is 0 by default.* @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database*            corruption, or null to use the default error handler.* @see #onBeforeDelete(SQLiteDatabase)* @see #SQLiteOpenHelper(Context, String, CursorFactory, int, DatabaseErrorHandler)* @see #onUpgrade(SQLiteDatabase, int, int)* @hide*/public SQLiteOpenHelper(@Nullable Context context, @Nullable String name,@Nullable CursorFactory factory, int version,int minimumSupportedVersion, @Nullable DatabaseErrorHandler errorHandler) {this(context, name, version, minimumSupportedVersion,new SQLiteDatabase.OpenParams.Builder());mOpenParamsBuilder.setCursorFactory(factory);mOpenParamsBuilder.setErrorHandler(errorHandler);}private SQLiteOpenHelper(@Nullable Context context, @Nullable String name, int version,int minimumSupportedVersion,@NonNull SQLiteDatabase.OpenParams.Builder openParamsBuilder) {Objects.requireNonNull(openParamsBuilder);if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);mContext = context;mName = name;mNewVersion = version;mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion);setOpenParamsBuilder(openParamsBuilder);}/*** Return the name of the SQLite database being opened, as given to* the constructor.*/public String getDatabaseName() {return mName;}/*** Enables or disables the use of write-ahead logging for the database.** Write-ahead logging cannot be used with read-only databases so the value of* this flag is ignored if the database is opened read-only.** @param enabled True if write-ahead logging should be enabled, false if it* should be disabled.** @see SQLiteDatabase#enableWriteAheadLogging()*/public void setWriteAheadLoggingEnabled(boolean enabled) {synchronized (this) {if (mOpenParamsBuilder.isWriteAheadLoggingEnabled() != enabled) {if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {if (enabled) {mDatabase.enableWriteAheadLogging();} else {mDatabase.disableWriteAheadLogging();}}mOpenParamsBuilder.setWriteAheadLoggingEnabled(enabled);}// Compatibility WAL is disabled if an app disables or enables WALmOpenParamsBuilder.removeOpenFlags(SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL);}}/*** Configures <a href="https://sqlite.org/malloc.html#lookaside">lookaside memory allocator</a>** <p>This method should be called from the constructor of the subclass,* before opening the database, since lookaside memory configuration can only be changed* when no connection is using it** <p>SQLite default settings will be used, if this method isn't called.* Use {@code setLookasideConfig(0,0)} to disable lookaside** <p><strong>Note:</strong> Provided slotSize/slotCount configuration is just a recommendation.* The system may choose different values depending on a device, e.g. lookaside allocations* can be disabled on low-RAM devices** @param slotSize The size in bytes of each lookaside slot.* @param slotCount The total number of lookaside memory slots per database connection.*/public void setLookasideConfig(@IntRange(from = 0) final int slotSize,@IntRange(from = 0) final int slotCount) {synchronized (this) {if (mDatabase != null && mDatabase.isOpen()) {throw new IllegalStateException("Lookaside memory config cannot be changed after opening the database");}mOpenParamsBuilder.setLookasideConfig(slotSize, slotCount);}}/*** Sets configuration parameters that are used for opening {@link SQLiteDatabase}.* <p>Please note that {@link SQLiteDatabase#CREATE_IF_NECESSARY} flag will always be set when* opening the database** @param openParams configuration parameters that are used for opening {@link SQLiteDatabase}.* @throws IllegalStateException if the database is already open*/public void setOpenParams(@NonNull SQLiteDatabase.OpenParams openParams) {Objects.requireNonNull(openParams);synchronized (this) {if (mDatabase != null && mDatabase.isOpen()) {throw new IllegalStateException("OpenParams cannot be set after opening the database");}setOpenParamsBuilder(new SQLiteDatabase.OpenParams.Builder(openParams));}}private void setOpenParamsBuilder(SQLiteDatabase.OpenParams.Builder openParamsBuilder) {mOpenParamsBuilder = openParamsBuilder;mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY);}/*** Sets the maximum number of milliseconds that SQLite connection is allowed to be idle* before it is closed and removed from the pool.** <p>This method should be called from the constructor of the subclass,* before opening the database** <p><b>DO NOT USE</b> this method.* This feature has negative side effects that are very hard to foresee.* See the javadoc of* {@link SQLiteDatabase.OpenParams.Builder#setIdleConnectionTimeout(long)}* for the details.** @param idleConnectionTimeoutMs timeout in milliseconds. Use {@link Long#MAX_VALUE} value* to allow unlimited idle connections.** @see SQLiteDatabase.OpenParams.Builder#setIdleConnectionTimeout(long)** @deprecated DO NOT USE this method. See the javadoc of* {@link SQLiteDatabase.OpenParams.Builder#setIdleConnectionTimeout(long)}* for the details.*/@Deprecatedpublic void setIdleConnectionTimeout(@IntRange(from = 0) final long idleConnectionTimeoutMs) {synchronized (this) {if (mDatabase != null && mDatabase.isOpen()) {throw new IllegalStateException("Connection timeout setting cannot be changed after opening the database");}mOpenParamsBuilder.setIdleConnectionTimeout(idleConnectionTimeoutMs);}}/*** Create and/or open a database that will be used for reading and writing.* The first time this is called, the database will be opened and* {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be* called.** <p>Once opened successfully, the database is cached, so you can* call this method every time you need to write to the database.* (Make sure to call {@link #close} when you no longer need the database.)* Errors such as bad permissions or a full disk may cause this method* to fail, but future attempts may succeed if the problem is fixed.</p>** <p class="caution">Database upgrade may take a long time, you* should not call this method from the application main thread, including* from {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.** @throws SQLiteException if the database cannot be opened for writing* @return a read/write database object valid until {@link #close} is called*/public SQLiteDatabase getWritableDatabase() {synchronized (this) {return getDatabaseLocked(true);}}/*** Create and/or open a database.  This will be the same object returned by* {@link #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 {@link #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.** <p class="caution">Like {@link #getWritableDatabase}, this method may* take a long time to return, so you should not call it from the* application main thread, including from* {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.** @throws SQLiteException if the database cannot be opened* @return a database object valid until {@link #getWritableDatabase}*     or {@link #close} is called.*/public SQLiteDatabase getReadableDatabase() {synchronized (this) {return getDatabaseLocked(false);}}private SQLiteDatabase getDatabaseLocked(boolean writable) {if (mDatabase != null) {if (!mDatabase.isOpen()) {// Darn!  The user closed the database by calling mDatabase.close().mDatabase = null;} else if (!writable || !mDatabase.isReadOnly()) {// The database is already open for business.return mDatabase;}}if (mIsInitializing) {throw new IllegalStateException("getDatabase called recursively");}SQLiteDatabase db = mDatabase;try {mIsInitializing = true;if (db != null) {if (writable && db.isReadOnly()) {db.reopenReadWrite();}} else if (mName == null) {db = SQLiteDatabase.createInMemory(mOpenParamsBuilder.build());} else {final File filePath = mContext.getDatabasePath(mName);SQLiteDatabase.OpenParams params = mOpenParamsBuilder.build();try {db = SQLiteDatabase.openDatabase(filePath, params);// Keep pre-O-MR1 behavior by resetting file permissions to 660setFilePermissionsForDb(filePath.getPath());} catch (SQLException ex) {if (writable) {throw ex;}Log.e(TAG, "Couldn't open " + mName+ " for writing (will try read-only):", ex);params = params.toBuilder().addOpenFlags(SQLiteDatabase.OPEN_READONLY).build();db = SQLiteDatabase.openDatabase(filePath, params);}}onConfigure(db);final int version = db.getVersion();if (version != mNewVersion) {if (db.isReadOnly()) {throw new SQLiteException("Can't upgrade read-only database from version " +db.getVersion() + " to " + mNewVersion + ": " + mName);}if (version > 0 && version < mMinimumSupportedVersion) {File databaseFile = new File(db.getPath());onBeforeDelete(db);db.close();if (SQLiteDatabase.deleteDatabase(databaseFile)) {mIsInitializing = false;return getDatabaseLocked(writable);} else {throw new IllegalStateException("Unable to delete obsolete database "+ mName + " with version " + version);}} else {db.beginTransaction();try {if (version == 0) {onCreate(db);} else {if (version > mNewVersion) {onDowngrade(db, version, mNewVersion);} else {onUpgrade(db, version, mNewVersion);}}db.setVersion(mNewVersion);db.setTransactionSuccessful();} finally {db.endTransaction();}}}onOpen(db);if (db.isReadOnly()) {Log.w(TAG, "Opened " + mName + " in read-only mode");}mDatabase = db;return db;} finally {mIsInitializing = false;if (db != null && db != mDatabase) {db.close();}}}private static void setFilePermissionsForDb(String dbPath) {int perms = FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP;FileUtils.setPermissions(dbPath, perms, -1, -1);}/*** Close any open database object.*/public synchronized void close() {if (mIsInitializing) throw new IllegalStateException("Closed during initialization");if (mDatabase != null && mDatabase.isOpen()) {mDatabase.close();mDatabase = null;}}/*** Called when the database connection is being configured, to enable features such as* write-ahead logging or foreign key support.* <p>* This method is called before {@link #onCreate}, {@link #onUpgrade}, {@link #onDowngrade}, or* {@link #onOpen} are called. It should not modify the database except to configure the* database connection as required.* </p>* <p>* This method should only call methods that configure the parameters of the database* connection, such as {@link SQLiteDatabase#enableWriteAheadLogging}* {@link SQLiteDatabase#setForeignKeyConstraintsEnabled}, {@link SQLiteDatabase#setLocale},* {@link SQLiteDatabase#setMaximumSize}, or executing PRAGMA statements.* </p>** @param db The database.*/public void onConfigure(SQLiteDatabase db) {}/*** Called before the database is deleted when the version returned by* {@link SQLiteDatabase#getVersion()} is lower than the minimum supported version passed (if at* all) while creating this helper. After the database is deleted, a fresh database with the* given version is created. This will be followed by {@link #onConfigure(SQLiteDatabase)} and* {@link #onCreate(SQLiteDatabase)} being called with a new SQLiteDatabase object** @param db the database opened with this helper* @see #SQLiteOpenHelper(Context, String, CursorFactory, int, int, DatabaseErrorHandler)* @hide*/public void onBeforeDelete(SQLiteDatabase db) {}/*** Called when the database is created for the first time. This is where the* creation of tables and the initial population of the tables should happen.** @param db The database.*/public abstract void onCreate(SQLiteDatabase db);/*** Called when the database needs to be upgraded. The implementation* should use this method to drop tables, add tables, or do anything else it* needs to upgrade to the new schema version.** <p>* The SQLite ALTER TABLE documentation can be found* <a href="http://sqlite.org/lang_altertable.html">here</a>. If you add new columns* you can use ALTER TABLE to insert them into a live table. If you rename or remove columns* you can use ALTER TABLE to rename the old table, then create the new table and then* populate the new table with the contents of the old table.* </p><p>* This method executes within a transaction.  If an exception is thrown, all changes* will automatically be rolled back.* </p>* <p>* <em>Important:</em> You should NOT modify an existing migration step from version X to X+1* once a build has been released containing that migration step.  If a migration step has an* error and it runs on a device, the step will NOT re-run itself in the future if a fix is made* to the migration step.</p>* <p>For example, suppose a migration step renames a database column from {@code foo} to* {@code bar} when the name should have been {@code baz}.  If that migration step is released* in a build and runs on a user's device, the column will be renamed to {@code bar}.  If the* developer subsequently edits this same migration step to change the name to {@code baz} as* intended, the user devices which have already run this step will still have the name* {@code bar}.  Instead, a NEW migration step should be created to correct the error and rename* {@code bar} to {@code baz}, ensuring the error is corrected on devices which have already run* the migration step with the error.</p>** @param db The database.* @param oldVersion The old database version.* @param newVersion The new database version.*/public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);/*** Called when the database needs to be downgraded. This is strictly similar to* {@link #onUpgrade} method, but is called whenever current version is newer than requested one.* However, this method is not abstract, so it is not mandatory for a customer to* implement it. If not overridden, default implementation will reject downgrade and* throws SQLiteException** <p>* This method executes within a transaction.  If an exception is thrown, all changes* will automatically be rolled back.* </p>** @param db The database.* @param oldVersion The old database version.* @param newVersion The new database version.*/public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {throw new SQLiteException("Can't downgrade database from version " +oldVersion + " to " + newVersion);}/*** Called when the database has been opened.  The implementation* should check {@link SQLiteDatabase#isReadOnly} before updating the* database.* <p>* This method is called after the database connection has been configured* and after the database schema has been created, upgraded or downgraded as necessary.* If the database connection must be configured in some way before the schema* is created, upgraded, or downgraded, do it in {@link #onConfigure} instead.* </p>** @param db The database.*/public void onOpen(SQLiteDatabase db) {}
}













本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/459795.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分布式搜索引擎elasticsearch操作文档操作介绍

1.DSL查询文档 elasticsearch的查询依然是基于JSON风格的DSL来实现的。 1.1.DSL查询分类 Elasticsearch提供了基于JSON的DSL&#xff08;Domain Specific Language&#xff09;来定义查询。常见的查询类型包括&#xff1a; 查询所有&#xff1a;查询出所有数据&#xff0c;…

软件系统安全保证措施,质量保证措施方案(Word原件套用)

系统安全保证措施是构建稳固防御体系的核心&#xff0c;旨在全方位保障信息系统的安全性。以下是对这七项措施的简要概述&#xff1a; 一、身份鉴别&#xff1a;采用多种认证方式&#xff0c;如密码、生物识别等&#xff0c;确保用户身份的准确无误&#xff0c;防止非法入侵。 …

玩转Docker | 使用Docker部署捕鱼网页小游戏

玩转Docker | 使用Docker部署捕鱼网页小游戏 一、项目介绍项目简介项目预览 二、系统要求环境要求环境检查Docker版本检查检查操作系统版本 三、部署捕鱼网页小游戏下载镜像创建容器检查容器状态下载项目内容查看服务监听端口安全设置 四、访问捕鱼网页小游戏五、总结 一、项目…

局域网 docker pull 使用代理拉取镜像

局域网 docker pull 使用代理拉取镜像 1、需求&#xff1a; 我有win主机&#xff0c;上面装有代理可连接dockerhub&#xff1b;我另有linux主机&#xff0c;直接pull因墙失败&#xff0c;想走win的代理访问dockerhub拉镜像&#xff1b;两台主机在同一个局域网中&#xff1b; …

c语言中结构体传参和实现位段

结构体传参 有两种方法: #include<stdio.h> struct S {int data[1000];int num; }; //结构体传参 void print1(struct S s) {printf("%d\n",s.num); } //结构体地址传参 void print2(struct S *ps) {printf("%d\n",ps->num); }int main() {pr…

2024年10月HarmonyOS应用开发者基础认证全新题库

注意事项&#xff1a;切记在考试之外的设备上打开题库进行搜索&#xff0c;防止切屏三次考试自动结束&#xff0c;题目是乱序&#xff0c;每次考试&#xff0c;选项的顺序都不同 这是基础认证题库&#xff0c;不是高级认证题库注意看清楚标题 高级认证题库地址&#xff1a;20…

HTML3D旋转相册

文章目录 序号目录1HTML满屏跳动的爱心(可写字)2HTML五彩缤纷的爱心3HTML满屏漂浮爱心4HTML情人节快乐

Depcheck——专门用于检测 JavaScript 和 Node.js 项目中未使用依赖项的工具

文章目录 Depcheck 是什麽核心功能&#x1f4da;检测未使用的依赖&#x1f41b;检测缺失的依赖✨支持多种文件类型&#x1f30d;可扩展性 安装与使用1. 安装 Depcheck2. 使用 Depcheck Depcheck 的应用总结项目源码&#xff1a; Depcheck 是什麽 来看一个常见错误场景&#x1…

Chrome和Firefox哪款浏览器的密码管理更安全

在当今数字化时代&#xff0c;浏览器已成为我们日常生活中不可或缺的工具。其中&#xff0c;谷歌Chrome和Mozilla Firefox是两款广受欢迎的浏览器。除了浏览网页外&#xff0c;它们还提供了密码管理功能&#xff0c;帮助用户保存和管理登录凭证。然而&#xff0c;关于哪款浏览器…

Camp4-L0:Linux 前置基础

书生浦语大模型实战营Camp4-L0:Linux前置基础 教程地址&#xff1a;https://github.com/InternLM/Tutorial/tree/camp4/docs/L0/linux任务地址&#xff1a;https://github.com/InternLM/Tutorial/blob/camp4/docs/L0/linux/task.md 任务描述完成所需时间闯关任务完成SSH连接与…

C++之多态的深度剖析

目录 前言 1.多态的概念 2.多态的定义及实现 2.1多态的构成条件 2.1.1重要条件 2.1.2 虚函数 2.1.3 虚函数的重写/覆盖 2.1.4 选择题 2.1.5 虚函数其他知识 协变&#xff08;了解&#xff09; 析构函数的重写 override 和 final关键字 3. 重载&#xff0c;重写&…

如何从iconfont中获取字体图标并应用到微信小程序中去?

下面我们一一个微信小程序的登录界面的制作为例来说明&#xff0c;如何从iconfont中获取字体图标是如何应用到微信小程序中去的。首先我们看效果。 这里所有的图标&#xff0c;都是从iconfont中以字体的形式来加载的&#xff0c;也就是说&#xff0c;我们自始至终没有使用一张…

Linux shell编程学习笔记87:blkid命令——获取块设备信息

0 引言 在进行系统安全检测时&#xff0c;我们需要收集块设备的信息&#xff0c;这些可以通过blkid命令来获取。 1 blkid命令的安装 blkid命令是基于libblkid库的命令行工具&#xff0c;可以在大多数Linux发行版中使用。 如果你的Linux系统中没有安装blkid命令&#xff0c;…

RuoYi-Vue 使用开发 人员管理-查询功能

说明&#xff1a;这里仅仅开发列表显示 与 查询功能&#xff0c;剩下的添加、修改等可能会遇到报错&#xff0c;后面有机会&#xff0c;会单独写一篇文章教学处理 1.了解开发需求 作为示例的二级开发&#xff0c;这里的人员管理&#xff0c;管理的是 部门信息&#xff0c;员工…

Tomcat 11 下载/安装 与基本使用

为什么要使用Tomcat&#xff1f; 使用Apache Tomcat的原因有很多&#xff0c;以下是一些主要的优点和特点&#xff1a; 1. 开源与免费 Tomcat是一个完全开源的项目&#xff0c;任何人都可以免费使用。它由Apache软件基金会维护&#xff0c;拥有一个活跃的社区&#xff0c;这…

Django入门教程——用户管理实现

第六章 用户管理实现 教学目的 复习数据的增删改查的实现。了解数据MD5加密算法以及实现模型表单中&#xff0c;自定义控件的使用中间件的原理和使用 需求分析 系统问题 员工档案涉及到员工的秘密&#xff0c;不能让任何人都可以看到&#xff0c;主要是人事部门进行数据的…

[ 问题解决篇 ] 解决远程桌面安全登录框的问题

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

微信小程序时间弹窗——年月日时分

需求 1、默认当前时间2、选择时间弹窗限制最大值、最小值3、每次弹起更新最大值为当前时间&#xff0c;默认值为上次选中时间4、 minDate: new Date(2023, 10, 1).getTime(),也可以传入时间字符串new Date(2023-10-1 12:22).getTime() html <view class"flex bb ptb…

【Spring框架】Spring框架的开发方式

目录 Spring框架开发方式前言具体案例导入依赖创建数据库表结构创建实体类编写持久层接口和实现类编写业务层接口和实现类配置文件的编写 IoC注解开发注解开发入门&#xff08;半注解&#xff09;IoC常用注解Spring纯注解方式开发 Spring整合JUnit测试 Spring框架开发方式 前言…

江协科技STM32学习- P24 DMA数据转运DMA+AD多通道

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…