![](/img/trans.png)
[英]How do I store a data from a fragment so it can be reuse in a MVVM architecture?
[英]Android MVVM Architecture Components: How do I update a single data entity from a list fragment?
我一直在努力学习新的Android架构组件。 我一直在将我的应用程序基于此示例: 基本示例
我有它工作,但我坚持如何插入,更新或删除Room数据库中的数据。 在示例中,它没有提供这些示例。
关于示例,我试图弄清楚如何从ProductListFragment对每个产品进行更改。 在我的应用程序中,我不是使用Product而是使用已定义的Zone。 因此,例如在列表中我想要一个按钮,按下时将删除该区域。 或者可以更新区域属性的按钮,例如区域具有活动属性。 当按钮单击该CardView时,它将更新区域的活动属性。
public class ZoneListFragment extends android.support.v4.app.Fragment {
public static final String TAG = "ZoneListViewModel";
private ZoneAdapter mZoneAdapter;
private FragmentZoneListBinding mBinding;
private ZoneListViewModel viewModel;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_zone_list, container, false);
mZoneAdapter = new ZoneAdapter(mZoneClickCallback, mZoneDirectionClickCallback);
mBinding.zonesList.setAdapter(mZoneAdapter);
return mBinding.getRoot();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
viewModel = ViewModelProviders.of(this).get(ZoneListViewModel.class);
subscribeUi(viewModel);
}
private void subscribeUi(ZoneListViewModel viewModel) {
// Update the list when the data changes
viewModel.getZones().observe(this, new Observer<List<ZoneEntity>>() {
@Override
public void onChanged(@Nullable List<ZoneEntity> myZones) {
if (myZones != null) {
mBinding.setIsLoading(false);
mZoneAdapter.setZoneList(myZones);
} else {
mBinding.setIsLoading(true);
}
mBinding.executePendingBindings();
}
});
}
private final ZoneClickCallback mZoneClickCallback = new ZoneClickCallback() {
@Override
public void onClick(Zone zone) {
}
};
private final ZoneDirectionClickCallback mZoneDirectionClickCallback = new ZoneDirectionClickCallback() {
@Override
public void onClick(Zone zone) {
zone.setDirection(zone.isDirection() ? false : true);
viewModel.updateZone(zone);
}
};
}
public class ZoneListViewModel extends AndroidViewModel {
private final MediatorLiveData<List<ZoneEntity>> mObservableZones;
private DataRepository repository;
public ZoneListViewModel(Application application) {
super(application);
mObservableZones = new MediatorLiveData<>();
// set by default null, until we get data from the database.
mObservableZones.setValue(null);
LiveData<List<ZoneEntity>> zones = ((Zoneify) application).getRepository()
.getZones();
// observe the changes of the zones from the database and forward them
mObservableZones.addSource(zones, mObservableZones::setValue);
}
public LiveData<List<ZoneEntity>> getZones() {
return mObservableZones;
}
}
public class ZoneAdapter extends RecyclerView.Adapter<ZoneAdapter.ZoneViewHolder> {
List<? extends Zone> mZoneList;
@Nullable
private final ZoneClickCallback mZoneClickCallback;
@Nullable
private final ZoneDirectionClickCallback mZoneDirectionClickCallback;
public ZoneAdapter(@Nullable ZoneClickCallback zoneClickCallback,
@Nullable ZoneDirectionClickCallback zoneDirectionClickCallback) {
mZoneClickCallback = zoneClickCallback;
mZoneDirectionClickCallback = zoneDirectionClickCallback;
}
public void setZoneList(final List<? extends Zone> zoneList) {
if (mZoneList == null) {
mZoneList = zoneList;
notifyItemRangeInserted(0, zoneList.size());
} else {
DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback() {
@Override
public int getOldListSize() {
return mZoneList.size();
}
@Override
public int getNewListSize() {
return zoneList.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return mZoneList.get(oldItemPosition).getId() ==
zoneList.get(newItemPosition).getId();
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
Zone newZone = zoneList.get(newItemPosition);
Zone oldZone = mZoneList.get(oldItemPosition);
return newZone.getId() == oldZone.getId()
&& Objects.equals(newZone.getName(), oldZone.getName())
&& Objects.equals(newZone.getAddress(), oldZone.getAddress())
&& newZone.isActive() == oldZone.isActive()
&& newZone.isDirection() == oldZone.isDirection()
&& Objects.equals(newZone.getLatLng(), oldZone.getLatLng())
&& Objects.equals(newZone.getNotification(), oldZone.getNotification());
}
});
mZoneList = zoneList;
result.dispatchUpdatesTo(this);
}
}
@Override
public ZoneViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ZoneItemBinding binding = DataBindingUtil
.inflate(LayoutInflater.from(parent.getContext()), R.layout.zone_item,
parent, false);
binding.setZoneClickcallback(mZoneClickCallback);
binding.setZoneDirectionClickCallback(mZoneDirectionClickCallback);
return new ZoneViewHolder(binding);
}
@Override
public void onBindViewHolder(ZoneViewHolder holder, int position) {
holder.binding.setZone(mZoneList.get(position));
holder.binding.executePendingBindings();
}
@Override
public int getItemCount() {
return mZoneList == null ? 0 : mZoneList.size();
}
static class ZoneViewHolder extends RecyclerView.ViewHolder {
final ZoneItemBinding binding;
public ZoneViewHolder(ZoneItemBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
}
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:map="http://schemas.android.com/tools">
<data>
<variable name="zone"
type="com.davidh.zoneify.data.model.Zone"/>
<variable name="zoneClickcallback"
type="com.davidh.zoneify.view.ZoneClickCallback"/>
<variable name="zoneDirectionClickCallback"
type="com.davidh.zoneify.view.ZoneDirectionClickCallback"/>
</data>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="100dp"
android:onClick="@{() -> callback.onClick(zone)}"
android:orientation="horizontal"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="125dp"
android:orientation="horizontal"
android:background="@color/colorPrimary">
<com.google.android.gms.maps.MapView
android:id="@+id/map"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
map:cameraZoom="15"
map:mapType="normal"
map:liteMode="true"
app:initMap="@{zone.latLng}"/>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="3"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:text="@{zone.name}"
android:textAppearance="@style/TextAppearance.AppCompat.Title.Inverse"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:text="@{zone.notification}"
android:textAppearance="@style/TextAppearance.AppCompat.Small.Inverse"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:layout_gravity="center|bottom">
<Button
android:layout_width="0dp"
android:layout_height="@dimen/imageButtonCardView"
android:layout_weight="1"
android:layout_gravity="center_horizontal|center|center_vertical"
android:background="@color/colorPrimary"
android:textAppearance="@style/TextAppearance.AppCompat.Widget.Button.Inverse"
style="?android:attr/borderlessButtonStyle"
android:id="@+id/btn_zone_direction"
android:drawableTop="@{zone.direction ? @drawable/ic_leaving_24 : @drawable/ic_entering_24}"
android:text="@{zone.direction ? @string/leaving : @string/entering}"
android:onClick="@{() -> directionCallback.onClick(zone)}"/>
<Button
android:layout_width="0dp"
android:layout_height="@dimen/imageButtonCardView"
android:layout_weight="1"
android:layout_gravity="center_horizontal|center|center_vertical"
android:background="@color/colorPrimary"
android:textAppearance="@style/TextAppearance.AppCompat.Widget.Button.Inverse"
style="?android:attr/borderlessButtonStyle"
android:id="@+id/btn_zone_active"
android:drawableTop="@{zone.active ? @drawable/ic_alarm_on_24 : @drawable/ic_alarm_off_24}"
android:text="@{zone.active ? @string/on : @string/off}"/>
<Button
android:layout_width="0dp"
android:layout_height="@dimen/imageButtonCardView"
android:layout_weight="1"
android:layout_gravity="center_horizontal|center|center_vertical"
android:background="@color/colorPrimary"
android:textAppearance="@style/TextAppearance.AppCompat.Widget.Button.Inverse"
style="?android:attr/borderlessButtonStyle"
android:id="@+id/btn_zone_edit"
android:drawableTop="@drawable/ic_edit_24"
android:text="@string/edit"
android:padding="@dimen/buttonCardViewPadding"/>
<Button
android:layout_width="0dp"
android:layout_height="@dimen/imageButtonCardView"
android:layout_weight="1"
android:layout_gravity="center_horizontal|center|center_vertical"
android:background="@color/colorPrimary"
android:textAppearance="@style/TextAppearance.AppCompat.Widget.Button.Inverse"
style="?android:attr/borderlessButtonStyle"
android:padding="@dimen/buttonCardViewPadding"
android:id="@+id/btn_zone_delete"
android:drawableTop="@drawable/ic_delete_24"
android:text="@string/delete"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</layout>
其余设置与基本示例中的相同。 只是坚持如何从列表中更新区域。
在删除/更新单击时,您将需要更新您的模型(您的存储库)。 存储库将发出一个新的LiveData
项,适配器将被更新, DiffUtils
将完成它的工作。 它将删除或更新该项目。
例如删除操作:
viewModel.deleteItem(id)
(这是你的ZoneListViewModel
) ViewModel
调用repository.deleteItem(id)
DiffUtils
一起删除该项目。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.