如何使用 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);
}
我正在尝试创建一个带有底部导航的应用程序,它可以在多个片段之间切换。
在其中一个中,我需要在 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);
}