【问题标题】:How to load data into a RecyclerView inside a fragment using ViewModel如何使用 ViewModel 将数据加载到片段内的 RecyclerView
【发布时间】:2021-08-30 20:18:27
【问题描述】:

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

在其中一个中,我需要在recyclerview 中列出数据。我对 android 比较陌生,我之前从未使用过 recyclerview 或 ViewModels 或 Fragments,所以我不能 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...这是如何工作的?

【问题讨论】:

    标签: java android android-fragments model-view-controller android-recyclerview


    【解决方案1】:

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

    【讨论】:

    • 我尝试在 fragment.java 中这样设置:private Observer&lt;ArrayList&lt;User&gt;&gt; userListUpdateObserver = new Observer&lt;ArrayList&lt;User&gt;&gt;() { @Override public void onChanged(ArrayList&lt;User&gt; userArrayList) { recyclerViewAdapter = new RecyclerViewAdapter(requireActivity(),userArrayList); recyclerView.setAdapter(recyclerViewAdapter); recyclerViewAdapter.notifyDataSetChanged(); } }; 但没有任何改变。放那个地方合适吗?
    • 我不会每次更改数据集时都更改适配器;适配器应该设置一次,然后当数据集改变时,它应该被通知。因为否则,您只是在浪费资源(因此,这不是最佳实践),我觉得这也是您问题的原因。
    • 如@FaisalKarim 所述,请删除 recyclerViewAdapter = new RecyclerViewAdapter(requireActivity(),userArrayList); recyclerView.setAdapter(recyclerViewAdapter);在观察者之外(在 onCreate 方法内,也做一些小的改变:recyclerViewAdapter = new RecyclerViewAdapter(requireActivity(), twoViewModel.userLiveData).),请在 recyclerViewAdapter.notifyDataSetChanged() 处放置一个断点;并调试以查看它是否真的在您的数据更改后调用该行。
    • 如果数据更改后没有打断点,请执行以下操作: twoViewModel.userLiveData.observe(this, data -> { recyclerViewAdapter.notifyDataSetChanged(); }); } 测试它保持在 onCreate 中。
    • 我把它移到了 onCreate 方法并设置了 recyclerViewAdapter.notifyDataSetChanged();我正在达到断点,但应用程序没有任何变化。我收到此错误:` 无法连接到 'pipe:qemud:wififorward' 服务:无效参数`,但我不知道这是否与此有关。一切似乎都被调用了,但是当我打开应用程序时,recyclerView 是空的。
    【解决方案2】:

    您的片段可能会观察到不同的 userLiveData 实例,这就是为什么每次您离开并返回片段时,回收器视图都是空的。要观察相同的 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);
        }
    

    【讨论】:

    • 我试过了,但同样的事情还在发生。
    【解决方案3】:

    尝试将 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 适配器更改为:

    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,它已经实现了。

    【讨论】:

      【解决方案4】:

      我在您的代码中看不到任何错误,除非您需要将 LayoutManager 设置为 RecyclerView

      recyclerView = root.findViewById(R.id.rv_main);
      recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); // <<< Add this
      recyclerView.setHasFixedSize(true);
      

      【讨论】:

      • 如果我在布局文件中设置app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager",还需要这样做吗?
      • 如果你在布局中这样做了,那么可能还有另一个问题;你可以在任何一个中做到这一点
      • @sundrycode 我有像你这样的样本,它工作正常。所以,提供的信息应该可以工作。如果你提供你的应用程序的演示,以便我们可以提供帮助
      • 当然,我该怎么做?
      • 大概可以上传到github或者其他代码共享平台
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-07
      相关资源
      最近更新 更多