Reputation: 127
In my MainActivity, I have items displayed in an Adapter. These items are Room Entity objects. When I click an item in the Adapter I start a DetailActivity.
Now in this DetailActivity, I'd like to get the clicked item using a ViewModel and the Entity object's ID.
My problem is, I'm not sure how to do this. Should I use LiveData? I'm confused because examples like this Google Codelab always wrap Entity objects in LiveData, so to get the object itself you have to observe changes with onChanged
and use the method's parameter.
My current approach is to use Intent putExtra
in MainActivity to send the item's ID to DetailActivity:
/** Called when an item in the places list is clicked.
*
* @param view The view displaying place name and address
* @param position The position of the place item
*/
@Override
public void onItemClick(View view, int position) {
// start DetailActivity
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra(EXTRA_PLACE_ID, adapter.getItem(position).getPlaceId());
// get the position that was clicked
// This will be used to save or delete the place from the DetailActivity buttons
clickedPlacePos = position;
startActivityForResult(intent, DETAIL_ACTIVITY_REQUEST_CODE);
}
Then in DetailActivity, after getting the ID, get Entity object by ID with ViewModel:
viewModel = new ViewModelProvider(this).get(PlaceViewModel.class);
Intent intent = getIntent();
if (intent.hasExtra(EXTRA_PLACE_ID)) {
String id = intent.getStringExtra(EXTRA_PLACE_ID);
viewModel.getPlaceById(id).observe(this, new Observer<PlaceModel>() {
@Override
public void onChanged(PlaceModel placeModel) {
// placeModel will be null if place is deleted
if (placeModel != null) {
place = placeModel;
// rest of code using this object is put here
}
}
});
}
Is this the usual approach to get a single item by ID? Or is there a simpler way?
It seems sort of complicated, and also all code that uses this object has to be placed inside onChanged
or else the object will be null. Also the Context of that code will no longer be DetailActivity. I'm new to Android.
The full code is here.
PlaceDao method:
@Query("SELECT * FROM place_table WHERE place_id =:id")
LiveData<PlaceModel> getPlaceById(String id);
PlaceRepository method:
LiveData<PlaceModel> getPlaceById(String id) {
return placeDao.getPlaceById(id);
}
PlaceViewModel:
import com.michaelhsieh.placetracker.model.PlaceModel;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
public class PlaceViewModel extends AndroidViewModel {
private PlaceRepository repository;
private LiveData<List<PlaceModel>> allPlaces;
public PlaceViewModel(@NonNull Application application) {
super(application);
repository = new PlaceRepository(application);
allPlaces = repository.getAllPlaces();
}
public LiveData<List<PlaceModel>> getAllPlaces() {
return allPlaces;
}
public LiveData<PlaceModel> getPlaceById(String id) {
return repository.getPlaceById(id);
}
public void insert(PlaceModel place) {
repository.insert(place);
}
public void delete(PlaceModel place) {
repository.delete(place);
}
public void update(PlaceModel place) {
repository.update(place);
}
}
Upvotes: 1
Views: 2505
Reputation: 81559
Is this the usual approach to get a single item by ID? Or is there a simpler way?
Usual approach yes, actually intended, modern way of doings things in Jetpack way no. But it's no surprise, Google didn't update most of their docs, and they didn't update most of their example resources in this regard.
Anyway, the intended way to do this is to rely on the SavedStateHandle, and Transformations.switchMap.
viewModel = new ViewModelProvider(this).get(PlaceViewModel.class);
// Intent intent = getIntent();
// if (intent.hasExtra(EXTRA_PLACE_ID)) {
// String id = intent.getStringExtra(EXTRA_PLACE_ID);
viewModel.getPlace().observe(this, new Observer<PlaceModel>() {
@Override
public void onChanged(PlaceModel placeModel) {
// placeModel will be null if place is deleted
if (placeModel != null) {
place = placeModel;
// rest of code using this object is put here
}
}
});
And
public class PlaceViewModel extends AndroidViewModel {
private PlaceRepository repository;
//private LiveData<List<PlaceModel>> allPlaces;
private LiveData<PlaceModel> place;
public PlaceViewModel(@NonNull Application application, @NonNull SavedStateHandle savedStateHandle) { // <-- activity 1.1.0+, lifecycle 2.2.0+
super(application);
repository = new PlaceRepository(application);
//allPlaces = repository.getAllPlaces();
place = Transformations.switchMap(savedStateHandle.<String>getLiveData(DetailActivity.EXTRA_PLACE_ID), (id) -> repository.getPlaceById(id));
}
//public LiveData<List<PlaceModel>> getAllPlaces() {
// return allPlaces;
//}
//public LiveData<PlaceModel> getPlaceById(String id) {
// return repository.getPlaceById(id);
//}
public LiveData<PlaceModel> getPlace() {
return place;
}
public void insert(PlaceModel place) {
repository.insert(place);
}
public void delete(PlaceModel place) {
repository.delete(place);
}
public void update(PlaceModel place) {
repository.update(place);
}
}
Upvotes: 1