英文:
Get item by ID using ViewModel
问题
在我的 MainActivity 中,我在一个适配器中显示了项目。这些项目是 Room 实体对象。当我点击适配器中的项目时,我启动了 DetailActivity。
现在在 DetailActivity 中,我想使用 ViewModel 和实体对象的 ID 来获取点击的项目。
我的问题是,我不确定如何做到这一点。我应该使用 LiveData 吗?我感到困惑,因为像这个Google Codelab这样的示例总是将实体对象包装在 LiveData 中,所以要获取对象本身,你必须观察onChanged
中的更改并使用方法的参数。
我目前的方法是在 MainActivity 中使用 Intent 的 putExtra
来发送项目的 ID 到 DetailActivity:
然后在 DetailActivity 中,在获取到ID后,使用 ViewModel 来根据ID获取实体对象:
这是获取单个项目的通常方法吗?还是有更简单的方法?
它似乎有点复杂,而且所有使用这个对象的代码都必须放在onChanged
中,否则对象将为空。而且该代码的上下文将不再是 DetailActivity。我是 Android 新手。
PlaceDao 方法:
@Query("SELECT * FROM place_table WHERE place_id = :id")
LiveData<PlaceModel> getPlaceById(String id);
PlaceRepository 方法:
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);
}
}
如果您有任何其他问题或需要进一步的帮助,请告诉我。
英文:
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);
}
}
答案1
得分: 1
Is this the usual approach to get a single item by ID? Or is there a simpler way?
通常的方法是通过ID获取单个项吗?还是有更简单的方法?
英文:
> 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);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论