Reputation: 179
I've been trying to learn the new Android Architecture Components. I've been basing my application off of this example: Basic Sample
I have it working, but I am stuck on how to insert, update or delete the data in the Room database. In the example it does not provide examples for those.
Going off of the example provided I am trying to figure out how to make changes to each Product from the ProductListFragment. In my application I am not using Product but a defined Zone. So for example in the list I want to have a button where when pressed will delete that Zone. Or a button that may update a property of the Zone, for example Zone has an active property. When the button is click on that CardView it will update the zone's active property.
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>
The rest of the setup is the same as in the Basic Sample. Just stuck on how to update a zone from the list.
Upvotes: 1
Views: 2463
Reputation: 13321
On delete/update click you will need to update your model (your repository). The repository will emit a new LiveData
item, the adapter will be updated and DiffUtils
will do it's job. It will either remove or update the item.
For example a delete action:
viewModel.deleteItem(id)
(this is your ZoneListViewModel
)ViewModel
call repository.deleteItem(id)
DiffUtils
will remove the item.Here is an example from android-architecture-blueprints
Upvotes: 5