0

I am currently working on a note taking app that follows the MVVM architecture. there are 2 activities. Main with the list of notes and view mode which allows the user to view the note. If they click on the description or title it then allows edit mode where you can save changes and what not. When a new note is being created, it takes the user to the same activity to view/edit notes and it enables edit mode with empty title and description. The problem im having at the moment is that if the user creates a note and decides to edit it right after it was created, when the user comes back to the list of notes it has a bunch of notes each containing each update he made so the note is getting saved into a new note instead of updating the existing one.

Code for save note:

private void saveNote(){

        //updates existing note. Next Statement adds new note
        if(getIntent().hasExtra(EXTRA_ID)){
            mViewTitle.setText(mEditTitle.getText().toString());
            String timeStamp = Utility.getCurrentTimestamp();
            timeStamp = timeStamp.replace("-", " ");

            Note note = new Note(mTitle, mContent, timeStamp);
            note.setId(mID);
            mAddEditNoteViewModel.update(note);
            Toast.makeText(this, "Note Updated", Toast.LENGTH_SHORT).show();
        } else if(!getIntent().hasExtra(EXTRA_ID)){
            mViewTitle.setText(mEditTitle.getText().toString());
            String timeStamp = Utility.getCurrentTimestamp();
            timeStamp = timeStamp.replace("-", " ");

            Note note = new Note(mTitle, mContent, timeStamp);
            mAddEditNoteViewModel.insert(note);
            Toast.makeText(this, "New Note Created:", Toast.LENGTH_SHORT).show();
        }
    }

as you can see, The way i check if i need to update or create a new note is by checking if the intent has the data i need (in this case the ID). But when the user just created the note and didnt go back to the main activity, every time the newly created note gets updated without going back to main would call the else if statement thus creating a new note. I can't seem to find a way to get around this. I was thinking of only saving the new note AFTER the user goes back to the main activity but if the user creates a note, clicks on the checkmark icon (to save) and closes the app without going back to main, the note will not be saved. How can i approach this problem?

2 Answers2

0

If I understand correctly, you are using the presence of the EXTRA_ID to determine whether the note currently being edited already exists.

But what the presence of EXTRA_ID really means is that the Activity was opened with an instruction to load an existing ID.

So these are not two equivalent meanings and you shouldn't be using EXTRA_ID as your test about whether to save a new note.

There are many ways to solve this. What I would do is change mID to mSavedNoteId and make it a nullable Integer or Long rather than an int or long. (Not sure which you're using.) Let a value of null indicate that you are not working with a saved note. When the activity opens, you can assign the value of mSavedNoteId based on the extra, or leave it as null if there is no extra. Only create the ID number and assign it to mSavedNoteId when it is first saved. And finally, your if statement can check whether mSavedNoteId is null or not to determine whether a new note should be saved or an existing one updated.

private void saveNote() {
    mViewTitle.setText(mEditTitle.getText().toString());
    String timeStamp = Utility.getCurrentTimestamp().replace("-", " ");
    Note note = new Note(mTitle, mContent, timeStamp);
    if (mSavedNoteId != null){
        note.setId(mSavedNoteId);
        mAddEditNoteViewModel.update(note);
        Toast.makeText(this, "Note Updated", Toast.LENGTH_SHORT).show();
    } else {
        mSavedNoteId = generateNewNoteId(); // however you're doing it
        note.setId(mSavedNoteId);
        mAddEditNoteViewModel.insert(note);
        Toast.makeText(this, "Note Updated", Toast.LENGTH_SHORT).show();
    } 
}

I suppose maybe it's your view model implementation that's generating an ID when you call insert(). In that case, make insert() return the ID that was generated and change the else branch like this:

mSavedNoteId = mAddEditNoteViewModel.insert(note);
Toast.makeText(this, "Note Updated", Toast.LENGTH_SHORT).show();
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • I did this but i have one problem. Im using a room database with autogenerate id. i changed my insert interface from void to Long and retrieved the value on the insert asynctask. The problem now is that when the app is first launched and i create a note, it will say that it was creaded with ID 0 but it really wasnt so when i update it shows it did update but once you go back it didnt. after that id create another one and the id would say ie 5 and i go back to main activity and click again but the id really was 6 –  Jan 09 '20 at 18:09
  • I'm not a Room user, but it sounds like you are not waiting for the returned value of the ID. Since it's asynchronous, you need to be able to pass a callback to your view model's `insert` method. So when you call insert, you should lock the edit button (use a boolean to guard the contents of its click listener), and then the callback can set the `mSavedNoteId` for you and unlock the edit button. – Tenfour04 Jan 09 '20 at 18:59
  • Careful about using AsyncTask. It's going to be deprecated in the next [Android release](https://stackoverflow.com/questions/58767733/android-asynctask-api-deprecating-in-android-11-what-are-the-alternatives). It'll probably work fine, but future examples probably won't feature it. – Tenfour04 Jan 09 '20 at 19:11
  • Yeah, that's what I was thinking. I'll approach it that way when I get home and look into the next release. Thank you! –  Jan 10 '20 at 01:38
0

I was able to get the result i wanted by doing the following:

in my repository, i return a long with the get method which returns the id being returned in the doInBackground method of the asynctask and unlike before (where the do in background was happening after the results from insert were delivered (null)) the result isnt delivered until doInBackground runs:

 public Long insert(Note note) {
        try {
            Long id = new InsertNoteAsyncTask(mNoteDao).execute(note).get();
            Log.d(TAG, "insert: CALLED - REPOSITORY - LONG: " + id);
            return id;
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

then the view model just gets and return the long

public Long insert(Note note) {
    return mNoteRepository.insert(note);
}

and everything works as expected. Big thanks to @Tenfour04 for the help