首页 > 解决方案 > getitemcount() 值在片段重新启动之前不会更新

问题描述

我的自定义适配器,当我添加任务时,getitemcount() 值不会增加,除非或直到它重新启动应用程序或在片段之间切换。并且 itemtouchelper 也不会更新 UI,除非我也为此执行相同的步骤。我正在使用 activityresult 方法来更新适配器。

public class CustomAdapterReminders extends RecyclerView.Adapter<CustomAdapterReminders.MyRecyclerView2> implements ItemMoveCallback.ItemTouchHelperContractReminder{
    private List<String[]> customListView;
    private String[] mRecentlyDeletedItem;
    private int mRecentlyDeletedItemPosition;
    private View snackbarView;
    private static final String dueDatedTime = "Due on: ";
    private Context context;
    public int positionAfterNewTAsk;

    public void setPositionAfterNewTAsk(int positionAfterNewTAsk) {
        this.positionAfterNewTAsk = positionAfterNewTAsk;
    }

    public CustomAdapterReminders(List<String[]> customListView) {
        this.customListView = customListView;
        Log.d("Item count" , String.valueOf(getItemCount()));
    }

    public CustomAdapterReminders() {
    }

    @NonNull
    @Override
    public MyRecyclerView2 onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View itemView = inflater.inflate(R.layout.recycler_item_reminders,parent,false);
        MyRecyclerView2 viewHolder = new MyRecyclerView2(itemView);
        snackbarView = parent.getRootView();
        return  viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyRecyclerView2 holder, int position) {
        String[] temp = customListView.get(position);
        holder.taskText.setText(temp[1]);
        holder.taskDate.setText(dueDatedTime + temp[2]);
    }

    public void changeData(){
        notifyDataSetChanged();
    }

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


    @Override
    public void onRowMoved(int fromPosition, int toPosition) {
        try {
            if (fromPosition < toPosition) {
                for (int i = fromPosition; i < toPosition; i++) {
                    Collections.swap(customListView, i, i + 1);
                }
            } else {
                for (int i = fromPosition; i > toPosition; i--) {
                    Collections.swap(customListView, i, i - 1);
                }
            }
            notifyItemMoved(fromPosition, toPosition);
        } catch (Exception ex) {
            Log.d("TAG", "Error in moving items");
        }
    }

    @Override
    public void onRowSelected(MyRecyclerView2 myViewHolder) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            myViewHolder.rowView.setBackgroundResource(R.drawable.border);
        }
    }

    @Override
    public void onItemDismiss(int position) {
        Log.d("Position", String.valueOf(position) +"Count"+ String.valueOf(getItemCount()) + "Pos" + positionAfterNewTAsk);
        String[] deleteIndex = customListView.get(position);
        mRecentlyDeletedItemPosition = position;
        mRecentlyDeletedItem = customListView.get(position);
        customListView.remove(position);
        TaskDBHelper taskDBHelper = new TaskDBHelper(context);
        final Handler handler = new Handler();
        showUndoSnackbar();
        handler.postDelayed(() -> taskDBHelper.DeleteFromReminders(deleteIndex[0]), 3000);
        notifyItemRemoved(position);
        notifyItemRangeChanged(position,getItemCount());
        positionAfterNewTAsk = 0;
    }


    @Override
    public void onRowClear(MyRecyclerView2 myViewHolder) {
        myViewHolder.rowView.setBackgroundResource(R.drawable.seleted_border);
    }

    private void undoDelete() {
        customListView.add(mRecentlyDeletedItemPosition,
                mRecentlyDeletedItem);
        notifyItemInserted(mRecentlyDeletedItemPosition);
        notifyItemRangeChanged(mRecentlyDeletedItemPosition,getItemCount());
    }

    private void showUndoSnackbar() {
        Snackbar.make(snackbarView, "Task deleted", Snackbar.LENGTH_LONG)
                .setAction("Undo", v -> undoDelete()).show();
    }

    public class MyRecyclerView2 extends RecyclerView.ViewHolder {
        TextView taskText, taskDate;
        View rowView;
        private MyRecyclerView2(@NonNull View itemView) {
            super(itemView);
            rowView = itemView;
            taskText = itemView.findViewById(R.id.reminderstextView);
            taskDate = itemView.findViewById(R.id.remindersDateView);
        }
    }
}


> **
  1. 在 recyclerview 上设置适配器的 Home Fragment

**

     public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        remindersViewModel = ViewModelProviders.of(this).get(RemindersViewModel.class);
        View root = inflater.inflate(R.layout.fragment_home, container, false);

        OneSignal.startInit(this.getContext())
                .inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification)
                .unsubscribeWhenNotificationsAreDisabled(true)
                .init();
        OneSignal.startInit(this.getContext())
                .setNotificationReceivedHandler(new ExampleNotificationReceivedHandler())
                .inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification)
                .unsubscribeWhenNotificationsAreDisabled(true)
                .init();

        setAdapter();
        FloatingActionButton fab = root.findViewById(R.id.floatingActionButton);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent addTask = new Intent(getActivity(), AddTask.class);
                startActivityForResult(addTask,ADD_TASK);
            }
        });
        return root;
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == 1) {
            refreshUI();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        setAdapter();
    }

    private void refreshUI() {
        setAdapter();
        adapter.changeData();

    }

    private void setAdapter() {
        try {
            taskDBHelper = new TaskDBHelper(this.getContext());
            try {
                taskList = taskDBHelper.browseReminders();
                adapter = new CustomAdapterReminders(taskList);
            }
            catch (Exception e){
                Log.d(TAG, "Exception in browsing");
            }
            staggaggeredGridLayoutManager = new StaggeredGridLayoutManager(2, 1);
            recyclerViewItems = getActivity().findViewById(R.id.rv);
            recyclerViewItems.setLayoutManager(staggaggeredGridLayoutManager);
            recyclerViewItems.setAdapter(adapter);
            adapter.changeData();
            ItemMoveCallback itemMoveCallback = new ItemMoveCallback();
            ItemTouchHelper.Callback callback = new ItemMoveCallback(adapter);
            touchHelper = new ItemTouchHelper(callback);
            touchHelper.attachToRecyclerView(recyclerViewItems);
        } catch (NullPointerException ex) {
            Log.d(TAG, "Exception in setAdapter");
        }
    }

    @Override
    public void requestDrag(RecyclerView.ViewHolder viewHolder) {
        touchHelper.startDrag(viewHolder);
    }

标签: androidandroid-recyclerviewcustom-adapter

解决方案


我想我可能知道问题出在哪里,但由于我还没有看到 addTask 类,所以在这一点上它是一个猜测。数据库操作通常是异步的,即不在主线程上完成,所以基本上当 onActivityResult 被调用时,不能保证 addTask 中的进程在您读取数据时完成将数据插入数据库。

一个简单的解决方法是重新排列代码的工作方式。您现在正在做的是用户决定添加一个任务,然后您将一些数据添加到数据库中(在 Addtask 中),然后您读取数据库中的内容并使用它使用 setAdapter 方法完全重置适配器。

相反,当用户决定添加任务时,将相应的String[]对象直接馈入customListView并调用通知数据集更改。同时您执行命令将相同的数据插入数据库。

因为您正在从主线程修改适配器,所以只有一切都会按顺序发生,并且您不会冒在插入操作发生之前读取数据库的风险。

另一种选择是您使用 Room 框架使用 LiveData 和 onChanged 侦听器来处理您的数据库。这意味着阅读文献需要付出很多努力,但是房间框架确实可以为您提供很多简化代码的功能


推荐阅读