提问人:Binari Dissanayake 提问时间:11/16/2023 最后编辑:MãĴďBinari Dissanayake 更新时间:11/19/2023 访问量:45
我的移动应用程序在删除项目时崩溃
My mobile application crashes when deleting item
问:
我正在尝试开发一个移动应用程序来熟悉SQLite数据库。在这里创建,add 方法正在工作。但是当我要在列表视图中删除时,移动应用程序崩溃了。这是我写的代码。
在 MainActivity.java 中
lv_customerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
CustomerModel clickedCustomer = (CustomerModel) parent.getItemAtPosition(position);
dataBaseHelper.deleteOne(clickedCustomer);
extracted(dataBaseHelper);
Toast.makeText(MainActivity.this, "Deleted" ,Toast.LENGTH_SHORT).show();
}
});
}
private void extracted(DataBaseHelper dataBaseHelper) {
customerArrayAdapter = new ArrayAdapter<CustomerModel>(MainActivity.this, android.R.layout.simple_list_item_1, dataBaseHelper.getEveryone());
lv_customerList.setAdapter(customerArrayAdapter);
}
}
在 databaseHelper.java 类中
`
public boolean deleteOne(CustomerModel customerModel){
SQLiteDatabase db = this.getWritableDatabase();
String queryString = "DELETE FROM" + CUSTOMER_TABLE + " WHERE " + COLUMN_ID + " = " + customerModel.getId();
Cursor cursor = db.rawQuery(queryString, null);
if(cursor.moveToFirst()){
return true;
}else {
return false;
}
}
答:
0赞
MikeT
11/19/2023
#1
您在关键字 FROM
和表名之间省略了空格,因此会遇到以下异常:
android.database.sqlite.SQLiteException: near "FROMcustomer": syntax error (code 1 SQLITE_ERROR): , while compiling: DELETE FROMcustomer WHERE _id = 9999
- 请注意,9999 是从客户那里提取的任何值。
但是,您总是会遇到该方法返回的 false 结果(请参阅下面的演示)。DeleteOne
这是由于双重问题:a) 该方法只能用于返回作为输出 SQL 语句提取的数据,即 SELECT 语句或某些 PRAGMA 语句,以及 b) 其他语句(如 DELETE)不返回任何内容,实际上会导致回滚撤消它们所做的操作。rawQuery
相反,您应该使用:-
一个方法,它同样不返回结果,
execSQL
exeSQL
做了要做的事情,可能什么都没有,或者失败了,或者
相应的便捷方法,例如删除方法。
delete
除了执行操作外,便捷方法还会返回适当的结果:-
- 该方法返回 ROWID 表的 rowid 或其别名
insert
- 和方法返回受影响的行数(删除或更新的行数)。
delete
update
- 该方法返回 ROWID 表的 rowid 或其别名
即便利方法在执行后调用相应的 SQLite API 函数以返回值
演示
以下是以下演示:
- DeleteOne 方法的工作(至少不会失败)版本,以及
- 使用该方法然后返回有用结果的示例,以及
execSQL
删除
便利方法的建议用法
以下是用于演示的 DatabaseHelper 类,该类基于可以从代码中确定的内容:-
class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "the_database";
public static final int DATABASE_VERSION = 1;
public static final String CUSTOMER_TABLE = "customer";
public static final String COLUMN_ID = BaseColumns._ID;
public static final String COLUMN_WHATEVER = "_whatever";
private DatabaseHelper(Context context) {
super(context,DATABASE_NAME,null,DATABASE_VERSION);
}
private static volatile DatabaseHelper instance;
public static DatabaseHelper getInstance(Context context) {
if (instance==null) {
instance = new DatabaseHelper(context);
}
return instance;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + CUSTOMER_TABLE +"(" +
COLUMN_ID + " INTEGER PRIMARY KEY" +
"," + COLUMN_WHATEVER + " TEXT" +
");"
);
}
@Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
}
public boolean deleteOne(/*CustomerModel customerModel*/ long id){
SQLiteDatabase db = this.getWritableDatabase();
String queryString = "DELETE FROM " + CUSTOMER_TABLE + " WHERE " + COLUMN_ID + " = " + /*customerModel.getId()*/ + id;
Cursor cursor = db.rawQuery(queryString, null);
if(cursor.moveToFirst()){
return true;
}else {
return false;
}
}
/* Using EXECSQL to return result */
public long DeleteByExecSQL(long id) {
SQLiteDatabase db = this.getWritableDatabase();
long beforeDeletionCount, afterDeletionCount;
db.beginTransaction();
beforeDeletionCount = getTableRowCount(CUSTOMER_TABLE,db);
db.execSQL("DELETE FROM " + CUSTOMER_TABLE + " WHERE " + COLUMN_ID + "=?",new String[]{String.valueOf(id)});
afterDeletionCount = getTableRowCount(CUSTOMER_TABLE,db);
db.setTransactionSuccessful();
db.endTransaction();
return beforeDeletionCount - afterDeletionCount;
}
/* Using Convenience DELETE */
public long DeleteViaConvenienceMethod(long id) {
SQLiteDatabase db = this.getWritableDatabase();
return db.delete(CUSTOMER_TABLE,COLUMN_ID+"=?",new String[]{String.valueOf(id)});
}
/* method to get the number of rows in the table */
public long getTableRowCount(String table, SQLiteDatabase db) {
long rv=0;
if (db == null) {
db = this.getWritableDatabase();
}
Cursor csr = db.query(table,new String[]{"count(*)"},null,null,null,null,null);
if (csr.moveToFirst()) rv = csr.getLong(0);
csr.close();
return rv;
}
/* Insert using the convenience INSERT method (returns rowid or alias thereof of inserted row) */
public long insertCustomer(Long id, String whatever) {
ContentValues cv = new ContentValues();
if (id!=null) cv.put(COLUMN_ID,id);
cv.put(COLUMN_WHATEVER,whatever);
return this.getWritableDatabase().insert(CUSTOMER_TABLE,null,cv);
}
/* for generated id */
public long insertCustomer(String whatever) {
return insertCustomer(null,whatever);
}
}
- 方法的更正版本
deleteOne
- 该方法使用 execSQL 方法进行删除,但也通过询问实际删除前后表中的行数并计算差值来返回已删除的行数。
deleteByExecSQL
- 建议的
deleteViaConvenienceMethod
- 其他方法支持上述内容。
- 请参阅评论。
为了实际演示这 3 种方法,以下活动代码:-
public class MainActivity extends AppCompatActivity {
DatabaseHelper dbh;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbh = DatabaseHelper.getInstance(this);
dbh.insertCustomer("C1");
dbh.insertCustomer("C2");
dbh.insertCustomer(100L,"C3");
dbh.insertCustomer("C4");
dbh.insertCustomer("C5");
try {
Log.d("DBINFO_DLT1_1","DELETED=" + dbh.deleteOne(9999));
Log.d("DBINFO_DLTE_1","DELETED=" + dbh.deleteByExecSQL(9999));
Log.d("DBINFO_DLTC_1","DELETED=" + dbh.deleteViaConvenienceMethod(9999));
Log.d("DBINFO_DLT1_2","DELETED="+dbh.deleteOne(100));
dbh.insertCustomer(100L,"C3");
Log.d("DBINFO_DLTE_2","DELETED=" + dbh.deleteByExecSQL(100));
dbh.insertCustomer(100L,"C3");
Log.d("DBINFO_DLTC_2","DELETED=" + dbh.deleteViaConvenienceMethod(100));
} catch (SQLiteException e) {
e.printStackTrace();
}
}
}
- 插入多行,其中一行提供特定 ID 100(要删除的行)
- 使用每种删除(或尝试删除)方法的两组:
- 第一组尝试删除 ID 为 9999 的不存在的行
- 第二组尝试删除 id 为 100 的现有行
- 删除后,将再次插入该行
- 日志记录围绕删除内容进行包装,以便可以从日志中提取结果
- try/catch 用于捕获遇到的任何错误
运行时,结果是:-
2023-11-19 12:20:27.995 D/DBINFO_DLT1_1: DELETED=false
2023-11-19 12:20:27.997 D/DBINFO_DLTE_1: DELETED=0
2023-11-19 12:20:27.997 D/DBINFO_DLTC_1: DELETED=0
2023-11-19 12:20:27.998 D/DBINFO_DLT1_2: DELETED=false
2023-11-19 12:20:28.000 D/DBINFO_DLTE_2: DELETED=1
2023-11-19 12:20:28.001 D/DBINFO_DLTC_2: DELETED=1
- 正如解释/预期的那样,即使删除了该行,deleteOne 方法也会返回 false(没有输出,因此无法进行 moveToFirst,即 ALWAYS FALSE)
- 其他两个方法返回实际删除的行数
- 显然,使用方便
删除
方法的代码更简单、更高效(它使用适当的 SQLite 接口),并且不会重新扫描表来获取计数- 根据获取行更改计数是使用 sqlite3_changes() 或 sqlite3_total_changes() 接口。
建议您参考 https://developer.android.com/studio/debug,这将使您能够确定初始问题。
评论