当前位置: 首页 > news >正文

南京网站制作建设/推广点击器

南京网站制作建设,推广点击器,最真实的招聘网站,男女做爰高清免费网站SQLiteOpenHelper SQLiteOpenHelper是Android开发中用于管理SQLite数据库的一个非常重要的工具类。以下是对SQLiteOpenHelper的详细介绍: 一、基本概念 SQLiteOpenHelper是一个抽象类,它主要用于管理数据库的创建和版本管理。通过继承这个类&#xff…

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) {}
}













相关文章:

Android的SQLiteOpenHelper类 笔记241027

SQLiteOpenHelper SQLiteOpenHelper是Android开发中用于管理SQLite数据库的一个非常重要的工具类。以下是对SQLiteOpenHelper的详细介绍&#xff1a; 一、基本概念 SQLiteOpenHelper是一个抽象类&#xff0c;它主要用于管理数据库的创建和版本管理。通过继承这个类&#xff…...

「Mac畅玩鸿蒙与硬件10」鸿蒙开发环境配置篇10 - 项目实战:计数器应用

本篇将通过一个简单的计数器应用,带你体验鸿蒙开发环境的实际操作流程。本项目主要练习组件的使用、事件响应和状态管理,帮助开发者熟悉基本的应用构建流程。 关键词 计数器应用组件操作事件响应状态管理HarmonyOS 应用开发一、创建计数器项目 1.1 在 DevEco Studio 中新建项…...

安卓逆向之ARM汇编寻址,汇编指令

一&#xff1a;ARM汇编寻址 1. 立即数寻址 (Immediate Addressing) 指令中直接给出一个常数值&#xff08;立即数&#xff09;&#xff0c;并对其进行操作。 MOV R0, #5 ; 将立即数5载入寄存器R02. 直接寻址 (Direct Addressing) 指令中给出的地址直接指定了内存中的一…...

Idea常见插件(超级实用)

文章目录 Idea好用的插件推荐Idea插件安装Chinese(中文版)Alibaba Java Coding Guidelines&#xff08;代码规范&#xff09;Auto Filling Java Arguments&#xff08;自动补全参数&#xff09;CamelCase&#xff08;变量名称格式转换&#xff09;CodeGeeX&#xff08;智能&…...

C++中如何获取时间并格式化为字符串?

在C中&#xff0c;你可以使用标准库中的 <chrono> 和 <iomanip> 头文件来获取当前时间并将其格式化为字符串。以下是一个简单的示例&#xff0c;展示了如何获取当前时间并将其格式化为一个可读的字符串&#xff08;例如&#xff1a;YYYY-MM-DD HH:MM:SS&#xff09…...

项目1 yolov5鱼苗检测计数

yolov5鱼苗检测 1. yolov5鱼苗检测1.1. 环境配置1.2 Predict1.3 Validate1.4 Train1.5 生成 ONNX 2 代码解析2.1 模型2.2 数据集2.3 损失函数2.4 训练2.5 预测 之前做的项目&#xff0c;再回顾一下 环境&#xff1a;GPU1卡&#xff0c;CPU4核&#xff0c;每显卡12GB&#xff0c…...

GPU 学习笔记三:GPU多机多卡组网和拓扑结构分析(基于数据中心分析)

文章目录 一、概述二、数据中心&#xff08;DC&#xff09;2.1 数据中心简介2.2 传统数据中心的网络模型2.3 脊叶网络模型&#xff08;Spine-Leaf&#xff09;2.4 Facebook的Fabric网络架构 三、基于数据中心的多机多卡拓扑3.1 Spine-Leaf 架构网络规模测算方法3.2 NVIDIA多机多…...

各编程语言处理HTTP状态码的库推荐

Http 状态码用那个库 备注 Spring 的状态码库为 org.springframework.http.HttpStatus Apache 的状态码库为&#xff1a; org.apache.http.HttpStatus 通常这 2 个库都差不多。 如你的项目中已经用了 Spring 的代码的话&#xff0c;那么就用 Spring 的库吧。 不管是那个库…...

【Mac】Python 环境管理工具

一、pyenv 1、安装 &#xff08;1&#xff09;安装 brew install pyenv&#xff08;2&#xff09;环境配置 查看系统使用 shell 是 bash 还是 zsh bash 配置文件&#xff1a;~/.bash_profile zsh 配置文件&#xff1a;~/.zshrc userMac ~ % echo $SHELL /bin/zsh userMa…...

大语言模型数据流程源码解读(基于llama3模型)

文章目录 前言一、数据进入LlamaForCausalLM(LlamaPreTrainedModel)类二、数据进入LlamaModel(LlamaPreTrainedModel)类1、input_ids的embedding编码2、position_ids位置获取3、causal_mask因果mask构建1、causal_mask调用2、因果mask代码解读(_update_causal_mask)4、hidden_s…...

[蓝桥杯 2015 省 A] 饮料换购

题目描述 乐羊羊饮料厂正在举办一次促销优惠活动。乐羊羊 C 型饮料&#xff0c;凭 3 个瓶盖可以再换一瓶 C 型饮料&#xff0c;并且可以一直循环下去(但不允许暂借或赊账)。 请你计算一下&#xff0c;如果小明不浪费瓶盖&#xff0c;尽量地参加活动&#xff0c;那么&#xff…...

K8S测试pod内存和CPU资源不足

只设置requests参数 mysql主从pod启动后监控 读压测之后 同时设置limits和requests&#xff0c;只调低内存值 监控 压力测试 同时设置limits和requests&#xff0c;只调低CPU值 初始状态 开始压测 结论 对于CPU&#xff0c;如果pod中服务使用CPU超过设置的limits&…...

rabbitmq 使用注意事项

1&#xff0c;注意开启的端口号&#xff0c;一共四个端口号&#xff0c;1883是mqtt连接的端口号&#xff0c;如果没开&#xff0c;是连接不上的需要手动起mqtt插件。 //开始mqtt插件服务 rabbitmq-plugins enable rabbitmq_mqtt 2&#xff0c;15672端口是http网页登录的管理后…...

<项目代码>YOLOv8 夜间车辆识别<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…...

xterm.js 库作用

前言&#xff1a;xterm.js 是一个用于在网页上模拟终端的强大 JavaScript 库。 一、在网页中实现终端模拟 1. 提供类似终端的界面 xterm.js可以在浏览器中创建一个看起来和行为都类似于传统终端的界面。这包括显示命令行提示符、接受用户输入、显示命令输出等。 例如&#…...

在Excel中如何快速筛选非特定颜色

Excel中的自动筛选是个非常强大的工具&#xff0c;不仅可以筛选内容&#xff0c;而且可以筛选颜色&#xff0c;例如筛选A列红色单元格。但是有时希望筛选除了红色之外的单元格&#xff08;下图右侧所示&#xff09;&#xff0c;其他单元格的填充色不固定&#xff0c;有几种颜色…...

kotlin定时器和主线程定时器

场景 最近要用kotlin写一个每隔一段时间切视频并截图 刷刷的就写出来了&#xff0c;很快啊 timerTask object : TimerTask() {override fun run() {captureWindow()if ((group 1) * 4 > urls.size) {showDialog()timerTask.cancel()timer.cancel()}groupupdatePlayers(…...

vscode不能执行vue命令/ vue : 无法加载文件

问题&#xff1a; 解决&#xff1a; 1. 在Windows应用中找到Windows PowerShell&#xff0c;以管理员运行&#xff1a; 2. 在命令框输入&#xff1a; set-ExecutionPolicy RemoteSigned&#xff0c; 然后输入A即可解决...

1.4 STL C++面试问题

1.4.1 说说STL的基本组成部分 总结 STL 的基本组成部分包括容器、算法、迭代器、函数对象和仿函数和适配器。通过这些组件&#xff0c;STL 提供了高效、灵活和可复用的代码结构&#xff0c;极大地提高了 C 的开发效率和程序的可维护性。STL 的设计思想使得算法和数据结构的使…...

Bash、sh 和 Shell都弄混了?

在Linux和Unix系统中&#xff0c;Bash、sh 和 Shell 都与命令行解释器相关&#xff0c;但它们各自的含义和作用略有不同。以下是它们之间的关系和区别&#xff1a; Shell Shell 是一个通用术语&#xff0c;指的是操作系统中负责解释和执行用户命令的程序。它是用户与操作系统…...

架构师备考专栏-导航页

简介 架构师备考专栏——软考系统架构师考试的学习宝典&#xff0c;集合了全面覆盖架构师考试大纲的精华文章。每篇文章都为本人手输,并校对数遍后发表&#xff0c;在此我保障每篇文章的质量绝对过关。诚邀对架构师软考感兴趣的朋友们收藏此页面&#xff0c;并根据个人所需高效…...

STM32-Cube定时器TIM

一、内部时钟源 1、创建项目 File → New → STM32 project选择STM32F103C8T6单片机&#xff0c;命名TIM 2、配置单片机 1.打开USART1&#xff0c;方便我们与电脑连接查看数据 开启UART1并开启中断。 2、设置时钟源 开启外部高速晶振 将时钟频率设置为72MHz 设置调试模…...

Webpack 是什么? 解决了什么问题? 核心流程是什么?

在前端开发中&#xff0c;Webpack 无疑是一个举足轻重的工具。它作为一个静态资源打包工具&#xff0c;能够帮助开发者将项目中的各种资源高效整合&#xff0c;以便于在浏览器中加载和执行。本文将深入探讨 Webpack 的核心功能、解决的问题以及 Webpack的核心流程。 Webpack是什…...

Jenkins面试整理-Jenkins 的主要用途是什么?

Jenkins 的主要用途 是在软件开发流程中实现自动化,尤其是在持续集成(CI)和持续交付/部署(CD)中。具体来说,Jenkins 的主要用途包括: 1. 持续集成(CI): ● Jenkins 自动从版本控制系统(如 Git、SVN)中拉取代码,自动化地编译、构建和测试代码。 ● 每当开发人员提…...

Linux下使用C/C++进行UDP网络编程

UDP 是User Datagram Protocol 的简称&#xff0c;中文名是用户数据报协议&#xff0c;是一种无连接、不可靠的协议&#xff0c;同样它也是工作在传顺层。它只是简单地实现从一端主机到另一端主机的数据传输功能&#xff0c;这些数据通过 IP 层发送&#xff0c;在网络中传输&am…...

【JavaEE初阶】网络原理—关于TCP协议值滑动窗口与流量控制,进来看看吧!!!

前言 &#x1f31f;&#x1f31f;本期讲解关于TCP协议的重要的机制“连接的建立和断开”~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1…...

无人机避障——使用三维PCD点云生成的2D栅格地图PGM做路径规划

着重介绍通过对三维 PCD 点云进行处理生成 2D 栅格地图 PGM&#xff0c;而后将该 PGM 地图充分运用到无人系统路径规划之中&#xff0c;使得无人机能够依据此规划合理避开飞行路线上可能出现的障碍物。&#xff08;解决如何使用PGM的问题&#xff09; Hybrid A*算法 参考博客…...

supermall项目上拉加载bug分析

1.bug分析 bug出现的过程是这样的&#xff1a;better-scroll框架会计算滚动内容的高度(通过BScroll对象的scrollerHeight属性记录滚动内容的高度) 由于内容中的图片资源还未加载成功 就已经完成计算 导致计算结果错误 而计算之后 图片资源随之加载完成 这时候better-scroll框架…...

【linux网络编程】| socket套接字 | 实现UDP协议聊天室

前言&#xff1a;本节内容将带友友们实现一个UDP协议的聊天室。 主要原理是客户端发送数据给服务端。 服务端将数据再转发给所有链接服务端的客户端。 所以&#xff0c; 我们主要就是要实现客户端以及服务端的逻辑代码。 那么&#xff0c; 接下来开始我们的学习吧。 ps:本节内容…...

第二届开放原子大赛-开源工业软件算法集成大赛即将启动!

第二届开放原子大赛-开源工业软件算法集成大赛作为开放原子开源基金会组织举办的开源技术领域专业赛事&#xff0c;聚焦开源底座框架平台建设&#xff0c;通过组件化集成的开发模式&#xff0c;丰富平台功能模块&#xff0c;拓展其应用场景&#xff0c;以此促进工业软件生态的繁…...