简体   繁体   中英

How to retrieve auto generated ID from Room when using LiveData?

I am creating an Android application which would store lists of values, eg. temperature values for different times under a particular user-defined name. I intend to use SQLite for storing the values, and I read that using Room would provide an ORM layer to it, so I used it. But then I ran into an exception which basically said that I cannot open a database connection from the main thread, so I tried using LiveData for insertion and retrieval purposes. Now I have 2 tables. I'm just trying to show the structure of them without being syntactically accurate:

**PLACE_DETAILS**
place_id integer auto_increment
place_name string
latitude double
longitude double

**TEMPERATURE_DETAILS**
temperature_id integer auto_increment
place_id foreign key references place_details(place_id)
time_of_record timestamp
temperature float

Initially, I thought of not enforcing the foreign key relationship and just retrieving the generated key when I insert the PLACE_DETAILS object, like what Hibernate does, and using it in further insertions into the TEMPERATURE_DETAILS table. However, from this question:

Room API - How to retrieve recently inserted generated id of the entity?

I found that the DAO method itself would need to return a long value representing the generated ID.

@Insert
long insertPlaceDetails(PlaceDetails placeDetails);

However, the AsyncTask which runs in the ViewModel needs to override the doInBackground() method which has Void as the return.

public class PlaceDetailsViewModel extends AndroidViewModel {

private final LiveData<List<PlaceDetails>> placeDetailsList;
private PlaceDatabase placeDatabase;

public PlaceDetailsViewModel(@NonNull Application application) {
    super(application);

    placeDatabase = PlaceDatabase.getDatabase(this.getApplication());
    placeDetailsList = placeDatabase.daoAccess().fetchAllPlaceDetails();
}

public LiveData<List<PlaceDetails>> getPlaceDetailsList() {
    return placeDetailsList;
}

public void addPlace(final PlaceDetails placeDetails) {
    Log.d("Adding", "Place: " + placeDetails.getPlaceName());
    new addAsyncTask(placeDatabase).execute(placeDetails);
}

private static class addAsyncTask extends AsyncTask<PlaceDetails, Void, Void> {

    private PlaceDatabase placeDatabase;

    addAsyncTask(PlaceDatabase placeDatabase) {
        this.placeDatabase = placeDatabase;
    }

    @Override
    protected Void doInBackground(PlaceDetails... placeDetails) {
        placeDatabase.daoAccess().insertPlaceDetails(placeDetails[0]);
        return null;
    }
}
}

So how could I actually retrieve the generated ID in my code? Also, if LiveData won't be able to provide me this value and relationship is the way to go, then also how do I insert values in the TEMPERATURE_DETAILS table based on the foreign key which has been auto-generated in the PLACE_DETAILS table? All the tutorials in the web give examples where they have given the id manually.

EDIT

According to the suggestions given by anhtuannd, I modified my VieModel class. But the value which is being returned is always -1. That itself shows that nothing is being inserted into the database. I have the WRITE_EXTERNAL_STORAGE permission in my manifest. Is anything else required for this to work?

public class PlaceDetailsViewModel extends AndroidViewModel {

private final LiveData<List<PlaceDetails>> placeDetailsList;
private PlaceDatabase placeDatabase;
private long insertId = -1;

public long getInsertId() {
    return insertId;
}

public PlaceDetailsViewModel(@NonNull Application application) {
    super(application);

    placeDatabase = PlaceDatabase.getDatabase(this.getApplication());
    placeDetailsList = placeDatabase.daoAccess().fetchAllPlaceDetails();
}

public LiveData<List<PlaceDetails>> getPlaceDetailsList() {
    return placeDetailsList;
}

public void onPlaceInserted(long id) {
    insertId = id;
}

public void addPlace(final PlaceDetails placeDetails) {
    Log.d("Adding", "Place: " + placeDetails.getPlaceName());
    new addAsyncTask(placeDatabase).execute(placeDetails);
}

private class addAsyncTask extends AsyncTask<PlaceDetails, Void, Void> {

    private PlaceDatabase placeDatabase;

    addAsyncTask(PlaceDatabase placeDatabase) {
        this.placeDatabase = placeDatabase;
    }

    @Override
    protected Void doInBackground(PlaceDetails... placeDetails) {
        insertId = placeDatabase.daoAccess().insertPlaceDetails(placeDetails[0]);
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);
        onPlaceInserted(insertId);
    }
}
}

I think you can get ID by using callback function in onPostExecute:

private static class addAsyncTask extends AsyncTask<PlaceDetails, Void, Void> {

    private PlaceDatabase placeDatabase;
    private PlaceDetails place;
    private int insertId = -1;

    addAsyncTask(PlaceDatabase placeDatabase) {
        this.placeDatabase = placeDatabase;
    }

    @Override
    protected Void doInBackground(PlaceDetails... placeDetails) {
        place = placeDetails[0];
        insertId = placeDatabase.daoAccess().insertPlaceDetails(place);
        return null;
    }

     @Override
     protected void onPostExecute(Void result) {
          super.onPostExecute(result);
          onPlaceInserted(insertId, place);
     }
}

void onPlaceInserted(int id, PlaceDetails place) {
    // you get ID here
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM