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 ButtononClickListener 以解决此问题,并通过发布的 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 更新行不起作用并且没有显示错误的主要内容,如果未能解决你的问题,请参考以下文章

在具有多个表的 sqlite 数据库中删除行不起作用

Android SQLite用户登录不起作用

Java JDBC SQLite 更新条目不起作用

iOS sqlite/FMDB 更新不起作用

如何在 SQLite Android 中提交?

带有日期字符串的 Android SQLite rawquery 在 WHERE 子句中不起作用