使用ViewModel按ID获取项目。

huangapple go评论107阅读模式
英文:

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&lt;PlaceModel&gt;() {
        @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(&quot;SELECT * FROM place_table WHERE place_id =:id&quot;)
LiveData&lt;PlaceModel&gt; getPlaceById(String id);

PlaceRepository method:

LiveData&lt;PlaceModel&gt; 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&lt;List&lt;PlaceModel&gt;&gt; allPlaces;


    public PlaceViewModel(@NonNull Application application) {
        super(application);
        repository = new PlaceRepository(application);
        allPlaces = repository.getAllPlaces();
    }

    public LiveData&lt;List&lt;PlaceModel&gt;&gt; getAllPlaces() {
        return allPlaces;
    }

    public LiveData&lt;PlaceModel&gt; 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&lt;PlaceModel&gt;() {
    @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&lt;List&lt;PlaceModel&gt;&gt; allPlaces;
    private LiveData&lt;PlaceModel&gt; place;


    public PlaceViewModel(@NonNull Application application, @NonNull SavedStateHandle savedStateHandle) { // &lt;-- activity 1.1.0+, lifecycle 2.2.0+
        super(application);
        repository = new PlaceRepository(application);
        //allPlaces = repository.getAllPlaces();
        place = Transformations.switchMap(savedStateHandle.&lt;String&gt;getLiveData(DetailActivity.EXTRA_PLACE_ID), (id) -&gt; repository.getPlaceById(id));
    }

    //public LiveData&lt;List&lt;PlaceModel&gt;&gt; getAllPlaces() {
    //    return allPlaces;
    //}

    //public LiveData&lt;PlaceModel&gt; getPlaceById(String id) {
    //    return repository.getPlaceById(id);
    //}

    public LiveData&lt;PlaceModel&gt; 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);
    }

}

huangapple
  • 本文由 发表于 2020年7月23日 06:52:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/63044293.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定