getitemcount() 值在片段重新启动之前不会更新

Posted

技术标签:

【中文标题】getitemcount() 值在片段重新启动之前不会更新【英文标题】:getitemcount() value not updating until the fragment is restarted 【发布时间】:2020-07-12 11:36:18 【问题描述】:

我的自定义适配器,当我添加一个任务时,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);
        
    



> **
    在 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);
    

【问题讨论】:

您似乎在另一个名为 addTask 的活动中将任务添加到 recyclerview 中,您尚未在代码中发布该活动。我还没有看到您将任务转换为字符串并将其添加到 customListView 的部分,这是一个字符串数组列表,也许您在添加任务后没有这样做 在那个活动中,我将任务字符串直接存储到数据库中(AddTask 在这里自行完成),并且 onActivityResult 再次调用 setAdapter ,它正在浏览数据库并填充 List 然后设置适配器再次。 所以每次执行 addTask 时都在完全重置适配器,为什么不直接在适配器内部重新填充 customListView 对象,然后调用 notifydatasetchanged。 所以我试了一下,taskList = taskDBHelper.browseReminders();适配器 = 新的 CustomAdapterReminders(taskList);适配器.notifyDataSetChanged();而不是重置适配器,但仍然索引超出范围 而不是每次都创建一个新适配器,只需更新您在适配器内绑定的列表 【参考方案1】:

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

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

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

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

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

【讨论】:

非常感谢您的帮助,它终于使用 OnResume 并使用 setter 更新适配器列表,然后调用 notifyDataSetChange()。

以上是关于getitemcount() 值在片段重新启动之前不会更新的主要内容,如果未能解决你的问题,请参考以下文章

Enmap (better-sqlite map) 在应用程序重新启动之前不会更新

当我们在android中使用backstack返回上一个片段时,上一个片段正在重新启动

重新启动时片段内部的 GLSurfaceView 不呈现

sh Unbounce脚本片段,用于在零停机时间内重新启动HAProxy

Kotlin:片段内的按钮需要在开始活动之前单击两次。如何一键启动活动?

NavHostFragment:使用导航抽屉重新打开更改的片段