如何使用 ViewModel 将数据加载到片段内的 RecyclerView 中

How to load data into a RecyclerView inside a fragment using ViewModel

我正在尝试创建一个带有底部导航的应用程序,它可以在多个片段之间切换。

在其中一个中,我需要在 recyclerview 中列出数据。我是 android 的新手,我以前从未使用过 recyclerview 或使用过 ViewModels 或片段,所以我不能 100% 确定我这样做是否正确。

这是我现在拥有的:

Fragment.java

public class twoFragment extends Fragment implements LifecycleOwner {

    private twoViewModel twoViewModel;
    private RecyclerView recyclerView;
    private RecyclerViewAdapter recyclerViewAdapter;

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {


        twoViewModel = new ViewModelProvider(this).get(twoViewModel.class);
        View root = inflater.inflate(R.layout.two, container, false);

        recyclerView = root.findViewById(R.id.rv_main);
        recyclerView.setHasFixedSize(true);

        twoViewModel.getUserMutableLiveData().observe(getViewLifecycleOwner(), userListUpdateObserver);


        return root;
    }

        private Observer<ArrayList<User>> userListUpdateObserver = new Observer<ArrayList<User>>() {
            @Override
            public void onChanged(ArrayList<User> userArrayList) {

                recyclerViewAdapter = new RecyclerViewAdapter(requireActivity(),userArrayList);
                recyclerView.setAdapter(recyclerViewAdapter);
            }
        };

}

ViewModel.java

public class twoViewModel  extends ViewModel {

    MutableLiveData<ArrayList<User>> userLiveData;
    ArrayList<User> userArrayList;

    public twoViewModel() {
        userLiveData = new MutableLiveData<>();

        // call your Rest API in init method
        init();
    }

    public MutableLiveData<ArrayList<User>> getUserMutableLiveData() {
        return userLiveData;
    }

    public void init(){
        populateList();
        userLiveData.setValue(userArrayList);
    }

    public void populateList(){

    User user = new User();
        user.setTitle("Darknight");
        user.setDescription("Best video ever!");

        userArrayList = new ArrayList<>();
        userArrayList.add(user);
        userArrayList.add(user);
        userArrayList.add(user);
        userArrayList.add(user);
        userArrayList.add(user);
        userArrayList.add(user);

}



}

RecyclerViewAdapter.java

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    Activity context;
    ArrayList<User> userArrayList;

    public RecyclerViewAdapter(Activity context, ArrayList<User> userArrayList) {
        this.context = context;
        this.userArrayList = userArrayList;
    }


    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View rootView = LayoutInflater.from(context).inflate(R.layout.item,parent,false);
        System.out.println("onCreateViewHolder");
        return new RecyclerViewViewHolder(rootView);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {

        User user = userArrayList.get(position);
        RecyclerViewViewHolder viewHolder= (RecyclerViewViewHolder) holder;

        viewHolder.txtView_title.setText(user.getTitle());
        viewHolder.txtView_description.setText(user.getDescription());
        viewHolder.imgView_icon.setImageDrawable(user.getImgIcon());
        System.out.println("onBindViewHolder");
    }

    @Override
    public int getItemCount() {
        return userArrayList.size();
    }

    class RecyclerViewViewHolder extends RecyclerView.ViewHolder {
        ImageView imgView_icon;
        TextView txtView_title;
        TextView txtView_description;

        public RecyclerViewViewHolder(@NonNull View itemView) {
            super(itemView);
            imgView_icon = itemView.findViewById(R.id.imgView_icon);
            txtView_title = itemView.findViewById(R.id.txtView_title);
            txtView_description = itemView.findViewById(R.id.txtView_description);
            System.out.println("RecyclerViewViewHolder");

        }
    }
}

问题

使用此代码,当我打开应用程序时,recyclerview 空的 。但是,当我单击片段中的 EditText 视图时,数据出现在 recyclerview 中。然后,当我离开碎片并返回时,它是空的。

我做错了什么?

我在某处读到你不应该同时使用 ViewModels 和 recyclerviews...这是如何工作的?

尝试在片段的 onchanged 方法中调用 recyclerViewAdapter.notifyDataSetChanged()。

除了您需要将 LayoutManager 设置为 RecyclerView

之外,我在您的代码中看不到任何错误
recyclerView = root.findViewById(R.id.rv_main);
recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); // <<< Add this
recyclerView.setHasFixedSize(true);

尝试将 twoFragment 更改为:

public class twoFragment extends Fragment {

private twoViewModel twoViewModel;
private RecyclerView recyclerView;
private RecyclerViewAdapter recyclerViewAdapter;

public View onCreateView(@NonNull LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState) {


    twoViewModel = new ViewModelProvider(this).get(twoViewModel.class);
    View root = inflater.inflate(R.layout.two, container, false);

    recyclerView = root.findViewById(R.id.rv_main);
    recyclerView.setHasFixedSize(true);
    
    recyclerViewAdapter = new RecyclerViewAdapter(requireContext());
    recyclerView.setAdapter(recyclerViewAdapter);

    twoViewModel.getUserMutableLiveData().observe(getViewLifecycleOwner(), userListUpdateObserver);


    return root;
}

    private Observer<ArrayList<User>> userListUpdateObserver = new Observer<ArrayList<User>>() {
        @Override
        public void onChanged(ArrayList<User> userArrayList) {
            recyclerView.setData(userArrayList);
        }
    };

}

并将 RecycleView Adapter 更改为:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

Context context;
ArrayList<User> userArrayList = ArrayList<User>();

public RecyclerViewAdapter(Context context) {
    this.context = context;
}

public setData(ArrayList<User> userArrayList){
    userArrayList = userArrayList;
    notifyDataSetChanged();
}


@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View rootView = LayoutInflater.from(context).inflate(R.layout.item,parent,false);
    System.out.println("onCreateViewHolder");
    return new RecyclerViewViewHolder(rootView);
}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {

    User user = userArrayList.get(position);
    RecyclerViewViewHolder viewHolder= (RecyclerViewViewHolder) holder;

    viewHolder.txtView_title.setText(user.getTitle());
    viewHolder.txtView_description.setText(user.getDescription());
    viewHolder.imgView_icon.setImageDrawable(user.getImgIcon());
    System.out.println("onBindViewHolder");
}

@Override
public int getItemCount() {
    return userArrayList.size();
}

class RecyclerViewViewHolder extends RecyclerView.ViewHolder {
    ImageView imgView_icon;
    TextView txtView_title;
    TextView txtView_description;

    public RecyclerViewViewHolder(@NonNull View itemView) {
        super(itemView);
        imgView_icon = itemView.findViewById(R.id.imgView_icon);
        txtView_title = itemView.findViewById(R.id.txtView_title);
        txtView_description = itemView.findViewById(R.id.txtView_description);
        System.out.println("RecyclerViewViewHolder");

    }
}
}

旁注:我很确定您不需要在片段上显式实现 LifeCyclerOwner,它已经实现了。

您的片段可能观察到不同的 userLiveData 实例,这就是为什么每次您离开并返回片段时,回收器视图都是 empty.To 观察相同的 userLiveData 实例使用下面的代码。

    public class twoViewModel  extends ViewModel {

    MutableLiveData<ArrayList<User>> userLiveData;
    ArrayList<User> userArrayList;

    public twoViewModel() {
        
        // call your Rest API in init method
        init();
    }

    public MutableLiveData<ArrayList<User>> getUserMutableLiveData() {
     if(userLiveData==null)
      userLiveData = new MutableLiveData<>();
        return userLiveData;
    }

public void init(){
        populateList();
        getUserMutableLiveData().setValue(userArrayList);
    }