У меня есть фрагмент (Inventory Fragment), который отображает некоторые объекты CardView в RecyclerView. Эти объекты получают свои данные от адаптера после того, как данные были получены от ViewModel. Внутри адаптера есть определенные функции, которые могут изменять Livedata. Все эти функции сначала открывают другой фрагмент (редактор продуктов), и в этом случае новые данные устанавливаются в ViewModel.
Моя проблема заключается в том, что даже после этого RecyclerView не получает новый объект. Я использовал notifyDataSetChanged()
. Что я делаю неправильно? Есть ли более простой способ добиться того, что я пытаюсь сделать (добавить, удалить, изменить и т. Д.)?
Фрагмент инвентаря:
package com.coffeetech.kittycatch;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
import java.util.List;
public class InventoryFragment extends Fragment {
//GLOBAL VARIABLES
RecyclerView recyclerView;
FoodAdapter foodAdapter;
FloatingActionButton add_button;
FrameLayout frameLayout;
FoodViewModel foodViewModel;
//FOOD LIST
private List<Food> foodList;
public InventoryFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_inventory, container, false);
//GETTING THE FOOD VIEW MODEL
foodViewModel = new ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication())).get(FoodViewModel.class); //TODO:HERE
foodList = foodViewModel.getFoods().getValue();
foodAdapter = new FoodAdapter(foodList);
recyclerView=v.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(foodAdapter);
//SETTING THE FOOD VIEW MODEL
foodViewModel.getFoods().observe(getActivity(), new Observer<List<Food>>() {
@Override
public void onChanged(List<Food> foods) {
foodAdapter.setFoods(foods);
foodList=foods;
foodAdapter.notifyDataSetChanged(); //TODO: MAKE THIS BETTER
}
});
//setting up the frameLayout
frameLayout = v.findViewById(R.id.food_editor_frame);
//setting up the Add button
add_button=v.findViewById(R.id.add_button);
add_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { //for new food addition to list
openFoodEditorFragment(-1);
}
});
foodAdapter.setOnFoodcardClickListener(new FoodAdapter.OnFoodcardClickListener() {
@Override
public void deleteFood(int position) { //code that deletes current food
foodViewModel.delete(foodList.get(position));
foodAdapter.notifyItemRemoved(position);
}
@Override
public void onEdit(int position) { //code that runs the edit of each food
openFoodEditorFragment(position);
foodAdapter.notifyItemChanged(position);
}
@Override
public void decrease(int position) {
foodList.get(position).decrease();
foodViewModel.update(foodList.get(position));
foodAdapter.notifyItemChanged(position);
}
@Override
public void increase(int position) {
foodList.get(position).increase();
foodViewModel.update(foodList.get(position));
foodAdapter.notifyItemChanged(position);
}
@Override
public void setSeekBar(int position,int progress) {
foodList.get(position).setQuantity(progress);
foodViewModel.update(foodList.get(position));
foodAdapter.notifyItemChanged(position);
}
});
return v;
}
public void openFoodEditorFragment(int position){ //position = -1 for new, and an integer (position) for edit
FoodEditorFragment foodEditorFragment;
switch(position){
case -1:
foodEditorFragment = new FoodEditorFragment(foodViewModel);
break;
default:
foodEditorFragment = new FoodEditorFragment(foodList.get(position),foodViewModel);
break;
}
FragmentTransaction transaction=getFragmentManager().beginTransaction();
transaction.replace(R.id.food_editor_frame,foodEditorFragment);
transaction.commit();
}
}
Адаптер RecyclerView:
package com.coffeetech.kittycatch;
import android.app.Application;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.FoodViewHolder> {
//VARIABLE THAT CONTAINS THE FOOD LIST (array list)
public List<Food> foods;
int size;
private OnFoodcardClickListener onFoodcardClickListener;
//listener interface
public interface OnFoodcardClickListener{
void deleteFood(int position);
void onEdit(int position);
void decrease(int position);
void increase(int position);
void setSeekBar(int position, int progress);
}
public void setOnFoodcardClickListener(OnFoodcardClickListener activity){ //this is called in MainActivity
onFoodcardClickListener=activity;
}
public FoodAdapter(List<Food>foods){
this.foods=foods;
}
public static class FoodViewHolder extends RecyclerView.ViewHolder{
//VARIABLES FOR EACH WIDGET IN FOODCARD
TextView name,quantity; //to modify according to current food
ImageButton decreaseButton,increaseButton; //to hide or show
SeekBar seekbar; //according to current type
ImageButton deleteButton,editButton;
public FoodViewHolder(@NonNull View itemView, final OnFoodcardClickListener listener) {//'itemView' is the card
super(itemView);
name=itemView.findViewById(R.id.name);
quantity=itemView.findViewById(R.id.quantity);
decreaseButton=itemView.findViewById(R.id.decrease_button);
increaseButton=itemView.findViewById(R.id.increase_button);
seekbar=itemView.findViewById(R.id.seekbar);
deleteButton=itemView.findViewById(R.id.delete_button);
editButton=itemView.findViewById(R.id.edit_button);
editButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.onEdit(position);
}
}
}
});
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.deleteFood(position);
}
}
}
});
decreaseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.decrease(position);
}
}
}
});
increaseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.increase(position);
}
}
}
});
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.setSeekBar(position,seekBar.getProgress());
}
}
}
});
}
}
@NonNull
@Override
public FoodViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.foodcard, parent, false); //inflating Foodcard
FoodViewHolder vw = new FoodViewHolder(v,onFoodcardClickListener);
return vw;
}
@Override
public void onBindViewHolder(@NonNull FoodViewHolder holder, int position) { //'holder' is the foodcard here
Food currentFood=foods.get(position);
holder.name.setText(currentFood.getName());
holder.quantity.setText(String.valueOf(currentFood.getQuantity()));
holder.seekbar.setProgress(currentFood.getQuantity());
//code to hide or show certain widgets based on food type
if(currentFood.getType()==0){ //for discrete food
holder.increaseButton.setVisibility(View.VISIBLE);
holder.decreaseButton.setVisibility(View.VISIBLE);
holder.quantity.setVisibility(View.VISIBLE);
holder.seekbar.setVisibility(View.GONE);
}else{// for continuous food
holder.increaseButton.setVisibility(View.GONE);
holder.decreaseButton.setVisibility(View.GONE);
holder.quantity.setVisibility(View.GONE);
holder.seekbar.setVisibility(View.VISIBLE);
}
}
@Override
public int getItemCount() {
return size;
}
//FUCNTION TO GET LIVE DATA HERE
public void setFoods (List<Food> foods){
this.foods=foods;
notifyDataSetChanged();
}
}
Фрагмент редактора продуктов питания:
package com.coffeetech.kittycatch;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
public class FoodEditorFragment extends Fragment {
private TextView name,quantity,min_quantity;
private ImageButton save,cancel;
private RadioGroup radioGroup;
protected int t,mode;
protected Food food;
FoodViewModel foodViewModel;
public FoodEditorFragment() {
// Required empty public constructor
}
public FoodEditorFragment (Food food, FoodViewModel foodViewModel){
this.food=food;
this.foodViewModel=foodViewModel;
mode=1;
}
public FoodEditorFragment (FoodViewModel foodViewModel){
this.foodViewModel=foodViewModel;
this.food = new Food();
mode=0;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_food_editor, container, false);
name=view.findViewById(R.id.name_editor);
quantity=view.findViewById(R.id.quantity_editor);
min_quantity=view.findViewById(R.id.min_quantity_editor);
save=view.findViewById(R.id.save_button_editor);
cancel=view.findViewById(R.id.cancel_button_editor);
radioGroup=view.findViewById(R.id.radioGroup_editor);
if (mode==1){ //for editing Food
//CODE TO SETUP EDITOR ACCORDING TO INITIAL DETAILS
name.setText(food.getName());
quantity.setText(String.valueOf(food.getQuantity()));
min_quantity.setText(String.valueOf(food.getMin_quantity()));
t=food.getType();
if(t==0){//for discrete food
radioGroup.check(R.id.discrete_radioButton);
}else{//for cont food
radioGroup.check(R.id.cont_radioButton);
}
}
setButtons();
return view;
}
public void setButtons(){
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { //USE BELOW 'food' TO PASS NEW DATA TO ACTIVITY
try {
if ((!name.getText().toString().isEmpty()) && ((radioGroup.getCheckedRadioButtonId() == R.id.discrete_radioButton) || (radioGroup.getCheckedRadioButtonId() == R.id.cont_radioButton))) {
food.setName(name.getText().toString());
food.setQuantity(Integer.parseInt(quantity.getText().toString()));
food.setMin_quantity(Integer.parseInt(min_quantity.getText().toString()));
if (radioGroup.getCheckedRadioButtonId() == R.id.discrete_radioButton) {
food.setType(0);
} else if (radioGroup.getCheckedRadioButtonId() == R.id.cont_radioButton) {
food.setType(1);
}
switch (mode){
case 0:
foodViewModel.insert(food);
break;
case 1:
foodViewModel.update(food);
break;
}
//CLOSE THE FRAGMENT
getFragmentManager().beginTransaction().remove(FoodEditorFragment.this).commit();
} else {
throw new Exception();
}
}catch (Exception e){
Toast.makeText(getContext(),"Please set all details",Toast.LENGTH_SHORT).show();
}
}
});
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { //CODE IF USER PRESSES ON CANCEL
//CLOSE THE FRAGMENT
getFragmentManager().beginTransaction().remove(FoodEditorFragment.this).commit();
}
});
}
}
ViewModel Я использую:
package com.coffeetech.kittycatch;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import java.util.ArrayList;
import java.util.List;
public class FoodViewModel extends AndroidViewModel {
private FoodRepository repository;
private LiveData<List<Food>> foods;
public FoodViewModel(@NonNull Application application) {
super(application);
repository = new FoodRepository(application);
foods=repository.getAll();
}
public void insert(Food food){
repository.insert(food);
}
public void update(Food food){
repository.update(food);
}
public void delete(Food food){
repository.delete(food);
}
public void deleteAll(){
repository.deleteAll();
}
public LiveData<List<Food>> getFoods(){
return foods;
}
public LiveData<List<Food>> getBuying () {return repository.getBuying();}
}