Andros Adrianopolos
Andros Adrianopolos

Reputation: 674

Room Database does not properly update the ID when data is added or removed

I am building an app that allows the user to store usernames & passwords. The user clicks on the FAB and the AddEditEntry.java activity starts. The user enters a username, enters or generates a password, enters a hint and clicks save. The new data is presented on a list in the Mainactivity.java. If the user chooses to edit the entry, all s/he needs to do is to long click the item and the same AddEditEntry.java class starts with the previous data in the fields. The user is then able to change that data and hit save to update the entry. There is also a button on the action bar to delete all entries or the user can swipe the entry left/right to remove it off of the database.

Instead, here is what happens:

The app is built with the MVVM architecture so I have (entity, DAO, database, repository, viewmodel) classes, as well as the necessary adapter class. I will post only the relevant code to avoid cluttering as much as possible. I can add more code per request.

MainActivity.java:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        //Sends the existing entry for editing
        adapter.setOnItemLongClickListener(new RecyclerViewAdapter.OnItemLongClickListener() {
            @Override
            public void onItemLongClick(Entries entries) {
                Intent intent = new Intent(MainActivity.this, AddEditEntry.class);

                intent.putExtra(AddEditEntry.EXTRA_USERNAME, entries.getUsername());
                intent.putExtra(AddEditEntry.EXTRA_HINT, entries.getHint());
                intent.putExtra(AddEditEntry.EXTRA_PASSWORD, entries.getPassword());
                intent.putExtra(AddEditEntry.EXTRA_ID, entries.getId());
                startActivityForResult(intent, EDIT_ENTRY_REQUEST);

                Toast.makeText(MainActivity.this, entries.getUsername(), Toast.LENGTH_SHORT).show();
                Toast.makeText(MainActivity.this, entries.getHint(), Toast.LENGTH_SHORT).show();
                Toast.makeText(MainActivity.this, entries.getPassword(), Toast.LENGTH_SHORT).show();
                Toast.makeText(MainActivity.this, String.valueOf(entries.getId()), Toast.LENGTH_SHORT).show();
            }
        });
    }
...
    //The onActivityResult retrieves the result when the user adds
    // or edits an entry by checking for the specific request code
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if(requestCode == ADD_ENTRY_REQUEST && resultCode == RESULT_OK){
            String username = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_USERNAME);
            String password = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_PASSWORD);
            String hint = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_HINT);

            Entries entry = new Entries(username, hint, password);
            viewModel.insert(entry);

            Toast.makeText(this, "Entry added!", Toast.LENGTH_SHORT).show();

        }else if(requestCode == EDIT_ENTRY_REQUEST && resultCode == RESULT_OK){
            int id = getIntent().getIntExtra(AddEditEntry.EXTRA_ID, -1);
            String username = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_USERNAME);
            String password = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_PASSWORD);
            String hint = Objects.requireNonNull(data).getStringExtra(AddEditEntry.EXTRA_HINT);

            if (id == -1){Toast.makeText(this, "Something went wrong", Toast.LENGTH_SHORT).show();}

            Entries entry = new Entries(username, hint, password);
            entry.setId(id);
            viewModel.update(entry);

            Toast.makeText(this, String.valueOf(id), Toast.LENGTH_SHORT).show();
            Toast.makeText(this, username, Toast.LENGTH_SHORT).show();
            Toast.makeText(this, password, Toast.LENGTH_SHORT).show();
            Toast.makeText(this, hint, Toast.LENGTH_SHORT).show();

            Toast.makeText(this, "Entry updated", Toast.LENGTH_SHORT).show();

        }else{Toast.makeText(this, "Entry not added!", Toast.LENGTH_SHORT).show();}
    }

AddEditEntry.java

public class AddEditEntry extends AppCompatActivity {

    public static final String EXTRA_USERNAME = "com.ozbek.cryptpass.EXTRA_USERNAME";
    public static final String EXTRA_HINT = "com.ozbek.cryptpass.EXTRA_HINT";
    public static final String EXTRA_PASSWORD = "com.ozbek.cryptpass.EXTRA_PASSWORD";
    public static final String EXTRA_ID = "com.ozbek.cryptpass.EXTRA_ID";
    public static final int EDIT_ENTRY_REQUEST = 3;

    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...

        final Intent intent = getIntent();
        // If the ID was passed, gets the extras for editing
        if(intent.hasExtra(EXTRA_ID)){
            setTitle("Edit Entry");
            saveEntry.setText("Update Entry");
            usernameEditText.setText(getIntent().getStringExtra(EXTRA_USERNAME));
            passwordEditText.setText(getIntent().getStringExtra(EXTRA_PASSWORD));
            hintEditText.setText(getIntent().getStringExtra(EXTRA_HINT));
            int id = getIntent().getIntExtra(EXTRA_ID, -1);

            Toast.makeText(this, "Info Received!!!", Toast.LENGTH_SHORT).show();
            Toast.makeText(this, getIntent().getStringExtra(EXTRA_USERNAME), Toast.LENGTH_SHORT).show();
            Toast.makeText(this, getIntent().getStringExtra(EXTRA_PASSWORD), Toast.LENGTH_SHORT).show();
            Toast.makeText(this, getIntent().getStringExtra(EXTRA_HINT), Toast.LENGTH_SHORT).show();
            Toast.makeText(this, String.valueOf(id), Toast.LENGTH_SHORT).show();
        }

        else{setTitle("Add Entry");}

        generatePassword.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {passwordEditText.setText(generatedPassword());}});

        saveEntry.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent data = new Intent();
                data.putExtra(EXTRA_USERNAME, usernameEditText.getText().toString());
                data.putExtra(EXTRA_HINT, hintEditText.getText().toString());
                data.putExtra(EXTRA_PASSWORD, passwordEditText.getText().toString());

                setResult(RESULT_OK, data);
                finish();
            }
        });
    }

    ...
}

EntryViewModel.java

public class EntryViewModel extends AndroidViewModel {
    private EntryRepository repository;
    private LiveData<List<Entries>> allEntries;


    public EntryViewModel(@NonNull Application application) {
        super(application);
        repository = new EntryRepository(application);
        allEntries = repository.getAllEntries();
    }

    public void insert(Entries entries){repository.insert(entries);}

    public void update(Entries entries){repository.update(entries);}

    public void delete(Entries entries){repository.delete(entries);}

    public void deleteAll(){repository.deleteAllEntries();}

    public LiveData<List<Entries>> getAllEntries() {return allEntries;}
}

Entries.java

@Entity(tableName = "entries_table")
public class Entries {
    @PrimaryKey(autoGenerate = true)
    private int id;

    private String username, hint, password;

    public Entries(String username, String hint, String password){
        this.username = username;
        this.hint = hint;
        this.password = password;
    }

    public Entries(){}

    public int getId() {return id;}

    public void setId(int id) {this.id = id;}

    public String getUsername() {return username;}

    public void setUsername(String username) {this.username = username;}

    public String getHint() {return hint;}

    public void setHint(String hint) {this.hint = hint;}

    public String getPassword() {return password;}

    public void setPassword(String password) {this.password = password;}
}

Here is the full source code

Upvotes: 1

Views: 83

Answers (2)

mchd
mchd

Reputation: 3163

Just add these fixes.

In the onClick() of your saveEntry (I assume its a button) in AddEditEntry.java, change it to this:

    saveEntry.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent data = new Intent();
            data.putExtra(EXTRA_USERNAME, usernameEditText.getText().toString());
            data.putExtra(EXTRA_HINT, hintEditText.getText().toString());
            data.putExtra(EXTRA_PASSWORD, passwordEditText.getText().toString());

            //You were missing these 2 lines
            int id  = getIntent().getIntExtra(EXTRA_ID, -1);
            if(id != -1){data.putExtra(EXTRA_ID, id);}

            setResult(RESULT_OK, data);
            finish();
        }
    });

And in the onActivityResult method inside your MainActivity.java, do this quick fix:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if(requestCode == ADD_ENTRY_REQUEST && resultCode == RESULT_OK){
        ...

    }else if(requestCode == EDIT_ENTRY_REQUEST && resultCode == RESULT_OK){
        int id = Objects.requireNonNull(data).getIntExtra(AddEditEntry.EXTRA_ID, -1);

        if (id == -1){
            Toast.makeText(this, "Something went wrong", Toast.LENGTH_SHORT).show();
            return;
        }

        ...

    }else{Toast.makeText(this, "Entry not added!", Toast.LENGTH_SHORT).show();}
}

It should work after these. Let me know if you got any issues.

Upvotes: 1

Nezih Yılmaz
Nezih Yılmaz

Reputation: 666

When the user deletes an entry (whether through swiping left/right or hitting the delete all button), the new entry does not start from the ID value of 1 onwards. The entry start from where the previous entry left off. So if I delete an entry with the ID = 1, the new entry's ID = 2.

This is the default behaviour of an auto generated primary key. What is wrong with it?

Even worse, when I hit the save button to update an entry, the ID becomes -1. And when this happens, the values for the entry do not exist at all because I'm checking them with Toast messages in each state. So there is no updating and the entry remains the same.

I did not read all of the code but this looks like a conflict issue. Try adding a replace strategy to your queries.

@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Entries entries);

@Update(onConflict = OnConflictStrategy.REPLACE)
void update(Entries entries);

Upvotes: 0

Related Questions