当前位置: 首页 > 知识库问答 >
问题:

OnBindViewHolder:为什么有时位置不从零开始?

丁念
2023-03-14

我正在使用RecyclerView,我注意到一个奇怪的行为:每次onBindViewHolder()被称为记录实际位置时,我都会放一个日志,有时位置不是从零开始的,你知道为什么吗?对我来说,这是一个问题,因为在位置0,我有不同的逻辑。

那是记录器:

2022-02-15 16:19:51.833 D/UpdateFragment: >>>ViewModel.GetAllCards()
2022-02-15 16:19:51.834 D/UpdateFragment: >>>ViewModel.GetAllTags()
2022-02-15 16:19:51.864 D/RecyclerViewAdapterUpdate: >>>Position:0
2022-02-15 16:19:52.110 D/RecyclerViewAdapterUpdate: >>>Position:1
2022-02-15 16:19:52.266 D/RecyclerViewAdapterUpdate: >>>Position:2
2022-02-15 16:19:52.331 D/RecyclerViewAdapterUpdate: >>>Position:3
2022-02-15 16:20:03.696 D/UpdateFragment: >>>ViewModel.GetAllCards()
2022-02-15 16:20:03.722 D/UpdateFragment: >>>ViewModel.GetAllCards()
2022-02-15 16:20:03.729 D/UpdateFragment: >>>ViewModel.GetAllCards()
2022-02-15 16:20:03.729 D/UpdateFragment: >>>ViewModel.GetAllCards()
2022-02-15 16:20:03.730 D/UpdateFragment: >>>ViewModel.GetAllCards()
2022-02-15 16:20:03.737 D/UpdateFragment: >>>ViewModel.GetAllCards()
2022-02-15 16:20:03.743 D/UpdateFragment: >>>ViewModel.GetAllCards()
2022-02-15 16:20:03.750 D/UpdateFragment: >>>ViewModel.GetAllCards()
2022-02-15 16:20:03.761 D/RecyclerViewAdapterUpdate: >>>Position:2
2022-02-15 16:20:03.830 D/RecyclerViewAdapterUpdate: >>>Position:3
2022-02-15 16:20:03.891 D/RecyclerViewAdapterUpdate: >>>Position:1
2022-02-15 16:20:04.042 D/RecyclerViewAdapterUpdate: >>>Position:0

好吧,我知道顺序并不总是一样的,但在我的应用程序中,当我更新数据时,我注意到两个ViewHolder的布局之间有一个神秘的交换,但在我的代码中,我从未为ViewHolder分配布局。正如您在日志中看到的,与位置相关联的布局id发生了变化。

2022-02-15 19:03:10.878 D/RecyclerViewAdapterUpdate: >>>Position[0]android.widget.LinearLayout{83f4271 G.E...... ......I. 0,0-0,0 #7f0800f5 app:id/layout_cards}
2022-02-15 19:03:11.593 D/RecyclerViewAdapterUpdate: >>>Position[1]android.widget.LinearLayout{e951d5e G.E...... ......I. 0,0-0,0 #7f0800f5 app:id/layout_cards}
2022-02-15 19:03:11.954 D/RecyclerViewAdapterUpdate: >>>Position[2]android.widget.LinearLayout{61b8127 G.E...... ......I. 0,0-0,0 #7f0800f5 app:id/layout_cards}
2022-02-15 19:03:18.326 D/RecyclerViewAdapterUpdate: >>>View android.widget.LinearLayout{61b8127 V.E...... ......I. 0,0-0,0 #7f0800f5 app:id/layout_cards}true
2022-02-15 19:03:18.953 D/RecyclerViewAdapterUpdate: >>>View androidx.constraintlayout.widget.ConstraintLayout{8510217 V.E...... ......I. 0,0-0,0 #7f08021e app:id/layout_update_card}true
2022-02-15 19:03:53.394 D/RecyclerViewAdapterUpdate: >>>Saved
2022-02-15 19:03:53.582 D/RecyclerViewAdapterUpdate: >>>Position[2]android.widget.LinearLayout{83f4271 G.E...... ......I. 0,0-0,0 #7f0800f5 app:id/layout_cards}
2022-02-15 19:03:53.729 D/RecyclerViewAdapterUpdate: >>>Position[1]android.widget.LinearLayout{e951d5e G.E...... ......I. 0,0-0,0 #7f0800f5 app:id/layout_cards}
2022-02-15 19:03:54.005 D/RecyclerViewAdapterUpdate: >>>Position[0]android.widget.LinearLayout{61b8127 V.E...... .......D 0,98-720,761 #7f0800f5 app:id/layout_cards}
2022-02-15 19:03:54.437 D/RecyclerViewAdapterUpdate: >>>Position[0]android.widget.LinearLayout{61b8127 V.E...... .......D 0,98-720,378 #7f0800f5 app:id/layout_cards}
2022-02-15 19:03:54.695 D/RecyclerViewAdapterUpdate: >>>Position[1]android.widget.LinearLayout{e951d5e G.E...... ......I. 0,0-0,0 #7f0800f5 app:id/layout_cards}
2022-02-15 19:03:54.879 D/RecyclerViewAdapterUpdate: >>>Position[2]android.widget.LinearLayout{83f4271 G.E...... ......I. 0,0-0,0 #7f0800f5 app:id/layout_cards}

public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

        Log.d(TAG, ">>>Position["+position+"]" + holder.linearLayout);
        if (position == 0) {

            // All the cards
            holder.numberOfItems.setText(String.valueOf(cardList.size()));
            holder.tagName.setText(R.string.all_cards_tag);
            holder.clearTag.setVisibility(View.GONE); // Can't delete all cards
            holder.checkBox.setChecked(allCardIsChecked);
            holder.checkBox.setOnClickListener(view -> {

                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putInt(Utilities.RECYCLER_CARD_POSITION, 0);
                editor.putBoolean(Utilities.SHOULD_SHUFFLE, true);

                if (holder.checkBox.isChecked()) {

                    MainActivity.recyclerTagList.clear();
                    editor.putStringSet(Utilities.SELECTED_TAGS, new HashSet<>());
                    Log.d(TAG, ">>Tags selected: " + MainActivity.recyclerTagList);

                    numberOfSelected = 1;
                    if (!allCardIsChecked) {
                        allCardIsChecked = true;
                        notifyDataSetChanged();
                    }

                } else {
                    // Can't deselect all cards, at least one group chosen
                    holder.checkBox.setChecked(true);
                    Toast.makeText(context, R.string.min_one_tag, Toast.LENGTH_SHORT).show();
                }

                editor.commit();

            });

            initializeLayoutCards(cardList,null,  holder, true);

        } else {

            // Single TAG after all cards
            Tag tag = tagList.get(position - 1);

            List<CardWithTags> listOfSingleTag = new ArrayList<>();
            for (CardWithTags cwt: cardList) {
                for (Tag t: cwt.getTagList()) {
                    if (t.getTag().equals(tag.getTag()))
                        listOfSingleTag.add(cwt);
                }
            }

            initializeLayoutCards(listOfSingleTag, tag, holder, false);

            holder.numberOfItems.setText(String.valueOf(listOfSingleTag.size()));
            holder.tagName.setText(tag.getTag());
            holder.clearTag.setVisibility(View.VISIBLE);
            if (allCardIsChecked)
                holder.checkBox.setChecked(false);
            else {
                holder.checkBox.setChecked(false);
                for (String s: selectedTags) {
                    if (s.equalsIgnoreCase(tag.getTag()))
                        holder.checkBox.setChecked(true);
                }
            }
            holder.checkBox.setOnClickListener(view -> {

                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putInt(Utilities.RECYCLER_CARD_POSITION, 0);
                editor.putBoolean(Utilities.SHOULD_SHUFFLE, true);

                if (holder.checkBox.isChecked()) {
                    MainActivity.recyclerTagList.add(tag);
                    selectedTags = sharedPreferences.getStringSet(Utilities.SELECTED_TAGS, new HashSet<>());
                    selectedTags.add(tag.getTag());
                    editor.putStringSet(Utilities.SELECTED_TAGS, selectedTags);
                    Log.d(TAG, ">>Tags selected: " + MainActivity.recyclerTagList);

                    if (allCardIsChecked) {
                        allCardIsChecked = false;
                        notifyDataSetChanged();
                    } else {
                        ++numberOfSelected;
                    }
                } else {
                    if (numberOfSelected == 1) {
                        Toast.makeText(context, R.string.min_one_tag, Toast.LENGTH_SHORT).show();
                        holder.checkBox.setChecked(true);
                    }
                    else {
                        --numberOfSelected;
                        MainActivity.recyclerTagList.removeIf(t -> t.getTag().equalsIgnoreCase(tag.getTag()));
                        selectedTags = sharedPreferences.getStringSet(Utilities.SELECTED_TAGS, new HashSet<>());
                        selectedTags.remove(tag.getTag());
                        editor.putStringSet(Utilities.SELECTED_TAGS, selectedTags);
                        Log.d(TAG, ">>Tags selected: " + MainActivity.recyclerTagList);
                    }
                }

                editor.commit();

            });

            View viewDialogTag = LayoutInflater.from(context).inflate(R.layout.dialog_modify_tag, (ViewGroup) null);
            EditText tagNameEditText = viewDialogTag.findViewById(R.id.tag_name_dialog);
            tagNameEditText.setText(tag.getTag());

            // In this way the dialog is created only one time
            AlertDialog dialogTag = getDialogUpdateTag(tag, viewDialogTag, tagNameEditText);
            AlertDialog dialogDeleteTag = getDialogDeleteTag(tag);

            holder.tagName.setOnLongClickListener( view -> {
                // Change tag name only if closed
                if (holder.linearLayout.getVisibility() == View.GONE)
                    dialogTag.show();
                return true;
            });

            holder.clearTag.setOnClickListener( view -> dialogDeleteTag.show());

        }

    }

private void initializeLayoutCards(List<CardWithTags> cardList, Tag tag, ViewHolder holder, boolean isAllCards) {

        // Or it will add already added cards
        holder.linearLayout.removeAllViews();

        for (CardWithTags cwt : cardList) {

            Card card = cwt.getCard();

            View cardView = LayoutInflater.from(context).inflate(R.layout.card_update, holder.linearLayout, false);
            TextView textViewCardName = cardView.findViewById(R.id.card_name);
            Button clearButton = cardView.findViewById(R.id.clear_card);
            ConstraintLayout layoutCardUpdate = cardView.findViewById(R.id.layout_update_card);
            EditText titleEditText = cardView.findViewById(R.id.update_title_edit_text);
            EditText taboo1EditText = cardView.findViewById(R.id.update_taboo_1_edit_text);
            EditText taboo2EditText = cardView.findViewById(R.id.update_taboo_2_edit_text);
            EditText taboo3EditText = cardView.findViewById(R.id.update_taboo_3_edit_text);
            EditText taboo4EditText = cardView.findViewById(R.id.update_taboo_4_edit_text);
            EditText taboo5EditText = cardView.findViewById(R.id.update_taboo_5_edit_text);
            Button saveButton = cardView.findViewById(R.id.save_button);
            Button tagButton = cardView.findViewById(R.id.tag_button);

            textViewCardName.setText(card.getTitle());
            titleEditText.setText(card.getTitle());
            taboo1EditText.setText(card.getTabooWord1());
            taboo2EditText.setText(card.getTabooWord2());
            taboo3EditText.setText(card.getTabooWord3());
            taboo4EditText.setText(card.getTabooWord4());
            taboo5EditText.setText(card.getTabooWord5());

            saveButton.setOnClickListener(view -> {

                Animations.doReduceIncreaseAnimation(view);

                String title = titleEditText.getText().toString();
                String taboo1 = taboo1EditText.getText().toString();
                String taboo2 = taboo2EditText.getText().toString();
                String taboo3 = taboo3EditText.getText().toString();
                String taboo4 = taboo4EditText.getText().toString();
                String taboo5 = taboo5EditText.getText().toString();

                if (title.equalsIgnoreCase(card.getTitle()) &&
                    taboo1.equalsIgnoreCase(card.getTabooWord1()) &&
                    taboo2.equalsIgnoreCase(card.getTabooWord2()) &&
                    taboo3.equalsIgnoreCase(card.getTabooWord3()) &&
                    taboo4.equalsIgnoreCase(card.getTabooWord4()) &&
                    taboo5.equalsIgnoreCase(card.getTabooWord5())) {
                    Log.d(TAG, ">>Change something before saving card");
                    return;
                }

                Card newCard = new Card(title, taboo1, taboo2, taboo3, taboo4, taboo5);
                newCard.setIdCard(card.getIdCard());

                // Check if new title already exists
                for (CardWithTags c: this.cardList) {
                    if (!c.getCard().getTitle().equalsIgnoreCase(card.getTitle()) && c.getCard().getTitle().equalsIgnoreCase(title)) {
                        Toast.makeText(context, R.string.title_already_exists, Toast.LENGTH_SHORT).show();
                        return;
                    }
                }

                cwt.setCard(newCard);
                Log.d(TAG, ">>New cwt: " + cwt);
                Log.d(TAG, ">>>Saved");
                viewModelFragment.updateCWT(cwt);
                Toast.makeText(context, R.string.card_updated, Toast.LENGTH_SHORT).show();
            });

            tagButton.setOnClickListener(view -> {

                Animations.doReduceIncreaseAnimation(view);
            });

            textViewCardName.setOnClickListener(view -> {
                openCloseView(layoutCardUpdate);
            });

            AlertDialog dialogDeleteCard;
            if (!isAllCards)
                dialogDeleteCard = getDialogDeleteCardOrTag(card, tag);
            else
                dialogDeleteCard = getDialogDeleteCard(card);

            clearButton.setOnClickListener(view -> dialogDeleteCard.show());

            // Set the click on both number of items and tag name
            holder.tagName.setOnClickListener(view -> {
                openCloseView(holder.linearLayout);
            });
            holder.numberOfItems.setOnClickListener(view -> {
                openCloseView(holder.linearLayout);
            });

            holder.linearLayout.addView(cardView);

        }

    }

    private void openCloseView(View view) {

        if (view.getVisibility() == View.GONE) {

            view.setVisibility(View.VISIBLE);
            boolean isVisible = view.getVisibility() == View.VISIBLE? true : false;
            Log.d(TAG, ">>>View " + view +isVisible);

            AnimationSet animation = new AnimationSet(true);
            Animation animationAlpha = new AlphaAnimation(0, 1);
            animation.addAnimation(animationAlpha);
            Animation animationTranslate = new TranslateAnimation(0, 0, -view.getHeight(), 0);
            animation.addAnimation(animationTranslate);
            Animation animationY = new ScaleAnimation(1, 1, 0, 1);
            animationY.setInterpolator(new LinearInterpolator());
            animation.addAnimation(animationY);
            animation.setDuration(200);

            view.startAnimation(animation);

        } else {

            AnimationSet animation = new AnimationSet(true);
            Animation animationAlpha = new AlphaAnimation(1, 0);
            animation.addAnimation(animationAlpha);
            Animation animationTranslate = new TranslateAnimation(0, 0, 0, -view.getHeight());
            animation.addAnimation(animationTranslate);
            Animation animationY = new ScaleAnimation(1, 1, 1, 0);
            animationY.setInterpolator(new LinearInterpolator());
            animation.addAnimation(animationY);
            animation.setDuration(200);

            animation.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {

                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    view.setVisibility(View.GONE);
                    boolean isVisible = view.getVisibility() == View.VISIBLE;
                    Log.d(TAG, ">>>View " + view +isVisible);
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });

            view.startAnimation(animation);
        }
    }

共有1个答案

南宫阳冰
2023-03-14

只绑定屏幕上需要更新的项目。事实上,组件试图最小化onbind调用的数量,以防止额外的工作。电话没有预定订单。因此,只有在第一次加载时才能确保调用0,即使在这种情况下也不会调用(例如,如果进行反向填充并从底部开始)。如果您编写的代码假设它总是试图绑定0,那么您就误解了RecyclerView的工作原理,需要重新评估您的设计

 类似资料:
  • 我正在将一个项目从Hibernate 4.2.6迁移到5.2.0。 persistence.xml文件如下所示 唯一的区别是setParameter中的0索引。 persistence.xml也非常相似

  • 问题内容: 我正在查看Mozilla的代码,该代码向Array添加了一个过滤器方法,并且其中的一行代码使我感到困惑。 我从未见过>>>在JavaScript中使用过。 这是什么,它做什么? 问题答案: 它不仅将非数字转换为数字,还将其转换为可以表示为32位无符号整数的数字。 虽然JavaScript的数字是双精度浮点(*),位运算符(,,,和)在对32位整数运算的定义。进行按位运算会将数字转换为3

  • 问题内容: 有谁知道为什么下面不等于0? 要么: 当我将其输入python时,它的值为1.22e-16。 问题答案: 该数字不能完全表示为浮点数。所以,不给你,它给你。 而其实类似。 那么,您如何处理呢? 您必须计算出或至少猜测出适当的绝对和/或相对误差范围,然后编写而不是: (这也意味着你要组织你的计算,使相对误差相对较大,而不是在你的情况,因为是恒定的,这是微不足道的,只是做了落后的。) Nu

  • 准备好了吗? 准备来开始我们的旅程!如果你就是那种从不看说明书的人,我推荐你还是回头看一下简介的最后一节。那里面讲了这个教学中你需要用到的工具及基本用法。我们首先要做的就是进入 ghc 的交互模式,接着就可以写几个函数体验一下 Haskell 了。打开终端机,输入 ghci,你会看到下列欢迎消息: GHCi,version6.8.2:http://www.haskell.org/ghc/ :?fo

  • 从零开始 欢迎您选择ILRuntime , 根据下面教程您可以快速的开始。 起步 在Unity2018以上版本中开始使用ILRuntime ILRuntime1.6版新增了Package Manager发布,使用Unity2018以上版本可以直接通过Package Manager安装,具体方法如下 如果你使用的是中国特别版Unity,那直接打开Package Manager即可找到ILRuntim

  • 问题内容: 我在ColdFusion代码中碰巧遇到了这些值,但Google计算器似乎有相同的“错误”,但差不为零。 416582.2850-411476.8100-5105.475 = -2.36468622461E-011 http://www.google.com/search?hl=zh_CN&rlz=1C1GGLS_enUS340US340&q=416582.2850+-+411476.8