Android SQLite 更新行不起作用并且没有显示错误
Posted
技术标签:
【中文标题】Android SQLite 更新行不起作用并且没有显示错误【英文标题】:Android SQLite update row not working and no errors shown 【发布时间】:2019-02-16 12:52:04 【问题描述】:我一直在尝试通过片段在 android 中通过 SQLite 更新行,但它不会更新表,我也没有收到任何错误。这是我的代码..也许我遗漏了一些东西。谢谢你
mysqliteHelper 类
public class MySQLiteHelper extends SQLiteOpenHelper
public static final String MYDATABASE = "myDataBase";
public static final String MYTABLE = "myTable";
public static final String USERNAME = "myUser";
public static final String PASSWORD = "myPass";
public static final String EMAIL = "myEmail";
public static final int VERSION = 1;
public static final String KEY_ID = "_id";
public MySQLiteHelper(Context context)
super(context, MYDATABASE, null, VERSION);
@Override
public void onCreate(SQLiteDatabase db)
String CREATE_TABLE = "CREATE TABLE " + MYTABLE + "("
+ KEY_ID + " INTEGER PRIMARY KEY," + USERNAME + " TEXT," + PASSWORD + " TEXT,"
+ EMAIL + " TEXT" + ")";
db.execSQL(CREATE_TABLE);
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
//any upgrade can update the version and if newV > oldV then upgrade will be exected
db.execSQL("DROP TABLE IF EXISTS " + MYTABLE);
onCreate(db);
public Integer deleteData(String id)
SQLiteDatabase db = this.getWritableDatabase();
return db.delete(MYTABLE, "_id = ?", new String[] id);
public boolean updateData(String id, String user, String pass, String email)
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(USERNAME, user);
cv.put(PASSWORD, pass);
cv.put(EMAIL, email);
db.update(MYTABLE, cv, "_id = ?", new String[] id);
return true;
主要活动类
public class MainActivity extends AppCompatActivity
private static final String TAG = "MainActivity";
EditText etUser, etPass, etEmail;
Button btSave, btShow;
MySQLiteHelper mySQLiteHelper;
SQLiteDatabase sqLiteDatabase;
ListView lvRecords;
ArrayList<String> userDataList;
ArrayAdapter<String> adapter;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: started");
etUser = findViewById(R.id.etUser);
etPass = findViewById(R.id.etPass);
etEmail = findViewById(R.id.etEmail);
btSave = findViewById(R.id.btSave);
btShow = findViewById(R.id.btShow);
lvRecords = findViewById(R.id.lvRecords);
userDataList = new ArrayList<String>();
mySQLiteHelper = new MySQLiteHelper(this);
sqLiteDatabase = mySQLiteHelper.getWritableDatabase(); //write and read
adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, userDataList);
lvRecords.setAdapter(adapter);
showList();
lvRecords.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener()
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
String selectedData = userDataList.get(position);
String rowId = selectedData.substring(0,1);
Log.d(TAG, "onItemLongClick: *******id " + rowId);
Integer deleteRow = mySQLiteHelper.deleteData(rowId);
adapter.remove(adapter.getItem(position));
adapter.notifyDataSetChanged();
Toast.makeText(MainActivity.this, "Position: " + rowId, Toast.LENGTH_SHORT).show();
return false;
);
lvRecords.setOnItemClickListener(new AdapterView.OnItemClickListener()
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
UpdateFragment updateFragment = new UpdateFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_container, updateFragment).addToBackStack(null).commit();
String selectedData = userDataList.get(position);
String[] userData = selectedData.split("\\s+");
String userId = userData[0];
String userName = userData[1];
String userPass = userData[2];
String userEmail = userData[3];
Bundle b = new Bundle();
b.putInt("position", position);
b.putString("id", userId);
b.putString("user", userName);
b.putString("pass", userPass);
b.putString("email", userEmail);
updateFragment.setArguments(b);
Toast.makeText(MainActivity.this, "id", Toast.LENGTH_SHORT).show();
);
btShow.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
showList();
);
btSave.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
//content values to put the data in the database
//same order as table creation fields order
ContentValues contentValues = new ContentValues();
String user = etUser.getText().toString();
String pass = etPass.getText().toString();
String email = etEmail.getText().toString();
contentValues.put(mySQLiteHelper.USERNAME, user);
contentValues.put(mySQLiteHelper.PASSWORD, pass);
contentValues.put(mySQLiteHelper.EMAIL, email);
sqLiteDatabase.insert(mySQLiteHelper.MYTABLE, null, contentValues);
hideKeyboard();
showList();
etUser.setText("");
etPass.setText("");
etEmail.setText("");
);
public void hideKeyboard()
InputMethodManager imm = (InputMethodManager) getSystemService(
Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
private void showList()
Cursor cursor = sqLiteDatabase.rawQuery("SELECT * FROM " + mySQLiteHelper.MYTABLE, null);
cursor.moveToFirst();
userDataList.clear();
//to read the first iteration use a do while
do
if(cursor != null)
int id = cursor.getInt(cursor.getColumnIndex(mySQLiteHelper.KEY_ID));
String user = cursor.getString(cursor.getColumnIndex(mySQLiteHelper.USERNAME));
String pass = cursor.getString(cursor.getColumnIndex(mySQLiteHelper.PASSWORD));
String email = cursor.getString(cursor.getColumnIndex(mySQLiteHelper.EMAIL));
userDataList.add(id + " " + user + " " + pass + " " + email);
adapter.notifyDataSetChanged();
Log.d(TAG, "onClick: ******rows: " + mySQLiteHelper.KEY_ID + ":" + id + " user: " + user + " pass: " + pass + " email: " + email);
Toast.makeText(MainActivity.this,
"id: " + id + " user: " + user + " pass: " + pass + " email: " + email, Toast.LENGTH_SHORT)
.show();
while(cursor.moveToNext());
UpdateFragment.class
public class UpdateFragment extends Fragment
private static final String TAG = "UpdateFragment";
Button btUpdate, btClose;
EditText etUser, etPass, etEmail;
Fragment me = this;
MySQLiteHelper mySQLiteHelper;
SQLiteDatabase sqLiteDatabase;
String userId, username, password, email;
int position, e;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
View v = inflater.inflate(R.layout.fragment_update, container, false);
etUser = v.findViewById(R.id.etUserFrag);
etPass = v.findViewById(R.id.etPassFrag);
etEmail = v.findViewById(R.id.etEmailFrag);
btUpdate = v.findViewById(R.id.btUpdateFrag);
btClose = v.findViewById(R.id.btCloseFrag);
Bundle b = getArguments();
position = b.getInt("position");
position = position -1;
userId = b.getString("id");
e = Integer.parseInt(userId);
//e = e - 1;
//userId = userId -1 ;
Log.d(TAG, "onCreateView: **********userID: " + userId);
username = b.getString("user");
password = b.getString("pass");
email = b.getString("email");
etUser.setText(username);
etPass.setText(password);
etEmail.setText(email);
mySQLiteHelper = new MySQLiteHelper(getContext());
sqLiteDatabase = mySQLiteHelper.getWritableDatabase(); //write and read
btClose.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
closeFragment();
);
btUpdate.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v) //
boolean isUpdate = mySQLiteHelper.updateData(userId, username, password, email);
if(isUpdate==true)
Toast.makeText(getContext(),"Data Update",Toast.LENGTH_LONG).show();
else
Toast.makeText(getContext(),"Data not Updated",Toast.LENGTH_LONG).show();
);
return v;
private void closeFragment()
getActivity().getSupportFragmentManager().beginTransaction().remove(me).commit();
【问题讨论】:
【参考方案1】:问题 1 空光标
绝不认为空游标为空。
返回 Cursor 的 SQLiteDatabase 方法将返回一个不为 null 的有效 Cursor。光标如果为空,则计数为 0(即cursor.getCount() == 0
)。
因此,如果您只是这样做(根据您的 showlist 方法)
cursor.moveToFirst();
if (cursor == null)
do you stuff here
如果光标为空,您将收到索引错误。相反,您应该检查cursor.moveToFirst()
的结果,如果现在提取了行,它将是错误的。然而,使用 while 循环更容易(参见下面的代码)。
问题 1-2 关闭光标
您还应该在完成后关闭光标。
更正/更好的 showList 方法:-
private void showList()
Cursor cursor = sqLiteDatabase.rawQuery("SELECT * FROM " + mySQLiteHelper.MYTABLE, null);
userDataList.clear();
//<<<<<<<<<< simpler while loop >>>>>>>>>>
while (cursor.moveToNext())
int id = cursor.getInt(cursor.getColumnIndex(mySQLiteHelper.KEY_ID));
String user = cursor.getString(cursor.getColumnIndex(mySQLiteHelper.USERNAME));
String pass = cursor.getString(cursor.getColumnIndex(mySQLiteHelper.PASSWORD));
String email = cursor.getString(cursor.getColumnIndex(mySQLiteHelper.EMAIL));
userDataList.add(id + " " + user + " " + pass + " " + email);
adapter.notifyDataSetChanged();
Log.d(TAG, "onClick: ******rows: " + mySQLiteHelper.KEY_ID + ":" + id + " user: " + user + " pass: " + pass + " email: " + email);
Toast.makeText(MainActivity.this,
"id: " + id + " user: " + user + " pass: " + pass + " email: " + email, Toast.LENGTH_SHORT)
.show();
cursor.close();
问题 2 - 未输入数据时保存。
如果您单击“保存”按钮并且没有在字段中输入数据,则会添加一个新行。如果在 ListView 中单击该项目,这将导致由于数组中的索引错误而崩溃,因为 split 不会提取 4 个项目(只有 id 是保证)。
以下内容将更正此问题(查看评论):-
btSave.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
//<<<<<<<<<< Start of Extra Code >>>>>>>>>>
if (
etUser.getText().toString().length() < 1 ||
etEmail.getText().toString().length() < 1 ||
etPass.getText().toString().length() < 1
)
Toast.makeText(MainActivity.this,"WHOA ENTER DATA IN ALL FIELDS!!!!!!!!!!",Toast.LENGTH_SHORT).show();
return;
//<<<<<<<<<< End of Extra Code >>>>>>>>>>
//content values to put the data in the database
//same order as table creation fields order
ContentValues contentValues = new ContentValues();
String user = etUser.getText().toString();
String pass = etPass.getText().toString();
String email = etEmail.getText().toString();
contentValues.put(mySQLiteHelper.USERNAME, user);
contentValues.put(mySQLiteHelper.PASSWORD, pass);
contentValues.put(mySQLiteHelper.EMAIL, email);
sqLiteDatabase.insert(mySQLiteHelper.MYTABLE, null, contentValues);
hideKeyboard();
showList();
etUser.setText("");
etPass.setText("");
etEmail.setText("");
);
问题 3 - updateData 方法总是返回 true
SQliteDatabase update 方法返回受影响的行数,因此如果没有更新行(将行更改为相同的值算作更新),将返回 0。您的 updateData 方法不会检查结果,因此总是返回 true。
也许改成:-
public boolean updateData(String id, String user, String pass, String email)
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(USERNAME, user);
cv.put(PASSWORD, pass);
cv.put(EMAIL, email);
if (db.update(MYTABLE, cv, "_id = ?", new String[] id) > 0)
return true;
return false;
为了提供更准确的反馈(并突出您的主要问题),可以添加以下方法以根据 id 获取数据:-
public Cursor getDataById(String id)
SQLiteDatabase db = this.getWritableDatabase();
String whereclause = KEY_ID + "=?";
String[] whereargs = new String[]String.valueOf(id);
return db.query(MYTABLE,null,whereclause,whereargs,null,null,null);
请注意,此功能的使用包含在下面的主要问题中。
主要问题
导致没有更新的主要问题是因为您将旧值传递给更新,而不是根据 EditTexts 的值。
以下代码更改了 UPDATE Button 的 onClickListener 以解决此问题,并通过发布的 Toast 提供更好的反馈:-
btUpdate.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v) //
//boolean isUpdate = mySQLiteHelper.updateData(userId, username, password, email);
boolean isUpdate = mySQLiteHelper.updateData(
userId,
etUser.getText().toString(),
etPass.getText().toString(),
etEmail.getText().toString()
);
Cursor csr = mySQLiteHelper.getDataById(userId);
String newUser = "not found";
String newEmail = "not found";
String newPass = "not found";
if (csr.moveToFirst())
newUser = csr.getString(csr.getColumnIndex(MySQLiteHelper.USERNAME));
newEmail = csr.getString(csr.getColumnIndex(MySQLiteHelper.EMAIL));
newPass = csr.getString(csr.getColumnIndex(MySQLiteHelper.PASSWORD));
csr.close();
if(isUpdate==true)
Toast.makeText(getContext(),
"Data Updated - User now " + newUser +
" Email now " + newEmail +
" Password now " + newPass,
Toast.LENGTH_LONG
).show();
else
Toast.makeText(getContext(),"Data not Updated - User is " + newUser +
" Email is " + newEmail +
" Password is " + newPass,
Toast.LENGTH_LONG
).show();
);
btUpdate.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
//boolean isUpdate = mySQLiteHelper.updateData(userId, username, password, email); //<<<<<<<<<< Commented out (old)
//<<<<<<<<<< NEW (gets values from the edit texts)
boolean isUpdate = mySQLiteHelper.updateData(
userId,
etUser.getText().toString(),
etPass.getText().toString(),
etEmail.getText().toString()
);
//<<<<<<<<<< ADDED to get current stored data for Toast
Cursor csr = mySQLiteHelper.getDataById(userId);
String newUser = "not found";
String newEmail = "not found";
String newPass = "not found";
if (csr.moveToFirst())
newUser = csr.getString(csr.getColumnIndex(MySQLiteHelper.USERNAME));
newEmail = csr.getString(csr.getColumnIndex(MySQLiteHelper.EMAIL));
newPass = csr.getString(csr.getColumnIndex(MySQLiteHelper.PASSWORD));
csr.close();
//<<<<<<<<< CHANGES so more info is provided by Toasts
if(isUpdate==true)
Toast.makeText(getContext(),
"Data Updated - User now " + newUser +
" Email now " + newEmail +
" Password now " + newPass,
Toast.LENGTH_LONG
).show();
else
Toast.makeText(getContext(),"Data not Updated - User is " + newUser +
" Email is " + newEmail +
" Password is " + newPass,
Toast.LENGTH_LONG
).show();
);
【讨论】:
哇,这是一个很好的答案,还有很多事情要做!非常感谢 !我是 SQLite 新手,所以这很有帮助。以上是关于Android SQLite 更新行不起作用并且没有显示错误的主要内容,如果未能解决你的问题,请参考以下文章