从 mvvm 获取的数据在第一次访问时不会在回收站视图中更新

Posted

技术标签:

【中文标题】从 mvvm 获取的数据在第一次访问时不会在回收站视图中更新【英文标题】:Fetched data from mvvm is not updated in recycler view on first visit 【发布时间】:2020-12-19 13:19:33 【问题描述】:

PreAdmissionList.java

public class PreAdmissionList extends Fragment implements View.OnClickListener, AdapterApprovalList.OnItemClickListener 

    private BasicInfoViewModel basicInfoViewModel;
    private AdapterApprovalList adapterApprovalList;
    private RecyclerView rvApprovalList;

    public PreAdmissionList() 
        // 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


        return inflater.inflate(R.layout.fragment_pre_admission_list, container, false);

    

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) 
        super.onViewCreated(view, savedInstanceState);
        view.findViewById(R.id.fab_add_new_admission).setOnClickListener(this);

        rvApprovalList = view.findViewById(R.id.rv_approval_list);


        basicInfoViewModel = new ViewModelProvider(requireActivity()).get(BasicInfoViewModel.class);
        basicInfoViewModel.init();
        basicInfoViewModel.getApprovalList().observe(getViewLifecycleOwner(), new Observer<List<ModelBasicInfo>>() 
            @Override
            public void onChanged(List<ModelBasicInfo> modelBasicInfos) 
                adapterApprovalList.notifyDataSetChanged();
            
        );
        initRecyclerView();

    

    private void initRecyclerView() 
        adapterApprovalList = new AdapterApprovalList(this,basicInfoViewModel.getApprovalList().getValue());
        rvApprovalList.setHasFixedSize(true);
        rvApprovalList.setLayoutManager(new LinearLayoutManager(getContext()));
        rvApprovalList.setAdapter(adapterApprovalList);
    



AdapterApprovalList.java

public class AdapterApprovalList extends RecyclerView.Adapter<AdapterApprovalList.ALViewHolder>

    private Context context;
    private OnItemClickListener onItemClickListener;

    private List<ModelBasicInfo> modelBasicInfoList;

    public AdapterApprovalList(OnItemClickListener onItemClickListener,List<ModelBasicInfo> modelBasicInfoList) 

        this.onItemClickListener = onItemClickListener;
        this.modelBasicInfoList=modelBasicInfoList;
    

    @NonNull
    @Override
    public ALViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
        context = parent.getContext();
        View view = LayoutInflater.from(context).inflate(R.layout.template_approval_list_item,parent,false);
        return new ALViewHolder(view,onItemClickListener);
    

    @Override
    public void onBindViewHolder(@NonNull ALViewHolder holder, int position) 
        ModelBasicInfo basicInfo = modelBasicInfoList.get(position);
        StringBuilder fullName = new StringBuilder();
        fullName.append(basicInfo.getFirstName()).append(" ");
        fullName.append(basicInfo.getMiddleName()).append(" ");
        fullName.append(basicInfo.getLastName()).append(" ");

        holder.fullName.setText(fullName);

        holder.id.setText("RKC00"+String.valueOf(basicInfo.getId()));
    

    @Override
    public int getItemCount() 
        return modelBasicInfoList.size();
    

    static class ALViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener 

        OnItemClickListener mOnItemClickListener;
        TextView fullName,id;
        public ALViewHolder(@NonNull View itemView,OnItemClickListener mOnItemClickListener) 
            super(itemView);
            this.mOnItemClickListener = mOnItemClickListener;
            fullName = itemView.findViewById(R.id.tv_text_full_name);
            id = itemView.findViewById(R.id.tv_text_approval_id);
            itemView.setOnClickListener(this);
        

        @Override
        public void onClick(View v) 
            mOnItemClickListener.onApprovalItemClick(getAbsoluteAdapterPosition());
        
    

    public interface OnItemClickListener
        void onApprovalItemClick(int position);
    



BasicInfoViewModel.java

public class BasicInfoViewModel extends ViewModel 

    private BasicInfoRepo basicInfoRepo;
    private MutableLiveData<List<ModelBasicInfo>> approvalList;

    public void init()
        if(approvalList != null)
            return;
        
        basicInfoRepo = BasicInfoRepo.getInstance();
        approvalList = basicInfoRepo.getApprovalList();
    

    public LiveData<List<ModelBasicInfo>> getApprovalList()
        return approvalList;
    

    public void insertBasicInfo(ModelBasicInfo modelBasicInfo)
        basicInfoRepo.insertData(modelBasicInfo);
    

    public void updateApprovalStatus(int id)
        basicInfoRepo.updateStatus(id);
    



BasicInfoRepo.java

public class BasicInfoRepo 

    private static BasicInfoRepo instance;

    static ConnectionClass connectionClass = new ConnectionClass();
    private List<ModelBasicInfo> approvalList = new ArrayList<>();


    public static BasicInfoRepo getInstance()
        if(instance== null)
            instance = new BasicInfoRepo();
        
        return instance;
    

    public MutableLiveData<List<ModelBasicInfo>> getApprovalList()
        loadApprovalList();
        MutableLiveData<List<ModelBasicInfo>> mList = new MutableLiveData<>();
        mList.setValue(approvalList);
        return mList;
    

    private void loadApprovalList() 
        LoadApprovalList loadApprovalList = new LoadApprovalList();
        loadApprovalList.execute();

    

    public void insertData(ModelBasicInfo modelBasicInfo)
        InsertBasicInfo insertBasicInfo = new InsertBasicInfo();
        insertBasicInfo.execute(modelBasicInfo);

    

    public void updateStatus(int id)
        UpdateBasicInfo updateBasicInfo = new UpdateBasicInfo();
        updateBasicInfo.execute(id);
    



    private static class InsertBasicInfo extends AsyncTask<ModelBasicInfo,Integer,String>

        @Override
        protected void onPreExecute() 
            super.onPreExecute();
        

        @Override
        protected String doInBackground(ModelBasicInfo... model) 
            String result = null;

//            Log.i("Testing db",lists[0].get(0).getFirstName());
            try
                Connection connection = connectionClass.CONN();
                if(connection==null)
                    result = "Error in connection !!!";
                else

                    //Date object
                    Date date= new Date();
                    //getTime() returns current time in milliseconds
                    long time = date.getTime();
                    //Passed the milliseconds to constructor of Timestamp class
                    Timestamp ts = new Timestamp(time);

                    PreparedStatement ps = connection.prepareStatement("insert into PreAdmissionDetails values(?,?,?,?,?,?,?,?,?,?)");
                    ps.setString(1,model[0].getFirstName());
                    ps.setString(2,model[0].getMiddleName());
                    ps.setString(3,model[0].getLastName());
                    ps.setString(4,model[0].getMotherName());
                    ps.setDate(5, java.sql.Date.valueOf(model[0].getDateOfBirth()));
                    ps.setString(6,model[0].getMobileNo());
                    ps.setInt(7,0);
                    ps.setInt(8,0);
                    ps.setBoolean(9,false);
                    ps.setTimestamp(10, ts);
                    ps.executeUpdate();
                    result = "Submitted Successfully !!!";

                

            catch (Exception ex)
                Log.e("sqlerror",ex.toString());
                result=ex.getMessage();
            
            Log.e("sqlerror","result : "+result);
            return result;
        


        @Override
        protected void onPostExecute(String s) 
            super.onPostExecute(s);
        

    

    private static class UpdateBasicInfo extends AsyncTask<Integer,Integer,String>


        @Override
        protected String doInBackground(Integer... integers) 

            String result = null;

            try
                Connection connection = connectionClass.CONN();
                if(connection==null)
                    result = "Error in connection !!!";
                else

                    PreparedStatement ps = connection.prepareStatement("UPDATE PreAdmissionDetails SET STATUS=? WHERE id=?");
                    ps.setInt(1,0);
                    ps.setInt(2,integers[0]);

                    ps.executeUpdate();
                    result = "Updated Successfully !!!";

                

            catch (Exception ex)
                Log.e("sqlerror",ex.toString());
                result=ex.getMessage();
            
            Log.e("sqlerror","result : "+result.toString());
            return result;

        
    

    private class LoadApprovalList extends AsyncTask<Void,Void,Void>
        @Override
        protected Void doInBackground(Void... voids) 
            String result = null;
            try
                Connection connection = connectionClass.CONN();
                if(connection==null)
                    result = "Error in connection !!!";
                else

                    PreparedStatement ps = connection.prepareStatement("select * from preadmissiondetails");
                    ResultSet rs = ps.executeQuery();
                    approvalList.clear();
                    while (rs.next()) 
                    approvalList.add(new ModelBasicInfo(rs.getInt(1),
                            rs.getString(2),
                            rs.getString(3),
                            rs.getString(4),
                            rs.getString(5),
                            rs.getString(6),
                            rs.getString(7),
                            rs.getInt(8),
                            rs.getInt(9),
                            rs.getBoolean(10)));

                    result = "Fetched Successfully !!!";

                

            catch (Exception ex)
                Log.e("sqlerror",ex.toString());
                result=ex.getMessage();
            
            Log.e("sqlerror","result : "+result.toString());

            return null;
        
    

问题就在这里,当我打开应用程序时,回收站视图中没有项目,我认为可能是互联网速度较慢,它会在一段时间后获取数据,但不显示数据。但是当我导航到其他一些片段并返回预录取列表时,它会显示数据。

【问题讨论】:

【参考方案1】:

你的问题在这里:

public MutableLiveData<List<ModelBasicInfo>> getApprovalList()
    loadApprovalList();
    MutableLiveData<List<ModelBasicInfo>> mList = new MutableLiveData<>();
    mList.setValue(approvalList);
    return mList;

loadApprovalList() 启动一个 AsyncTask,这是一个异步操作(换句话说,产生结果需要时间)。 getApprovalList() 方法不只是停在那里等待loadApprovalList() 完成。它继续并在第一次执行时返回一个空列表。但是到第二次执行时,approvalList 现在有了一个值,因为 AsyncTask 已经完成。所以它在第二次执行时返回正确的数据。当您返回 Fragment 时,它会再次执行,因为您的 ViewModel 中的 init 块此时正在执行第二次。

解决方案是将approvalList 设为 LiveData。这样,当 AsyncTask 更新approvalList 时,您的ViewModel 可以观察到变化。您的 ViewModel 应该在您的 Repository 中观察 approvalList,就像您的 Fragment 如何在您的 ViewModel 中观察 getApprovalList() 方法一样。

【讨论】:

以上是关于从 mvvm 获取的数据在第一次访问时不会在回收站视图中更新的主要内容,如果未能解决你的问题,请参考以下文章

如何在MVVM架构中观察RecyclerView适配器中的LiveData?

在 MVVM 应用程序中访问核心数据堆栈

将数据传回 MVVM

无法使用MVVM通过Xceed CheckListBox获取SelectedItems

如何使用 mvvm 模式从不同的 ViewModel 获取属性和调用命令

[DataGridCheckBoxColumn在属性更改时不会在MVVM中更新