Android RecyclerView: informDataSetChanged () IllegalStateException


130

ฉันกำลังพยายามอัปเดตรายการของ recycleview โดยใช้ informDataSetChanged ()

นี่คือเมธอด onBindViewHolder () ของฉันในอะแดปเตอร์ recycleview

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {

     //checkbox view listener
    viewHolder.getCheckbox().setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

            //update list items
            notifyDataSetChanged();
        }
    });
}

สิ่งที่ฉันต้องการทำคืออัปเดตรายการหลังจากฉันทำเครื่องหมายในช่อง ฉันได้รับข้อยกเว้นที่ผิดกฎหมายแม้ว่า:"Cannot call this method while RecyclerView is computing a layout or scrolling"

java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
    at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:1462)
    at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onChanged(RecyclerView.java:2982)
    at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyChanged(RecyclerView.java:7493)
    at android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged(RecyclerView.java:4338)
    at com.app.myapp.screens.RecycleAdapter.onRowSelect(RecycleAdapter.java:111)

ฉันยังใช้ alertItemChanged () ข้อยกเว้นเดียวกัน วิธีที่เป็นความลับในการอัปเดตเพื่อแจ้งอแด็ปเตอร์ว่ามีอะไรเปลี่ยนแปลงหรือไม่?


ตอนนี้ฉันมีปัญหาเดียวกันนี้ การใส่ setoncheckchanged listener ในตัวสร้าง Viewholder ทำให้ฉันมีข้อผิดพลาดเหมือนกัน
filthy_wizard

คำตอบ:


145

คุณควรย้ายเมธอด 'setOnCheckedChangeListener ()' ไปที่ ViewHolder ซึ่งเป็นคลาสภายในบนอะแดปเตอร์ของคุณ

onBindViewHolder()ViewHolderไม่ได้เป็นวิธีการที่เริ่มต้น วิธีนี้เป็นขั้นตอนของการรีเฟรชรายการรีไซเคิลแต่ละรายการ เมื่อคุณโทรnotifyDataSetChanged(), onBindViewHolder()จะถูกเรียกว่าเป็นตัวเลขของแต่ละครั้งรายการ

ดังนั้นหากคุณnotifyDataSetChanged()ใส่onCheckChanged()และเริ่มต้น checkBox ในonBindViewHolder()คุณจะได้รับ IllegalStateException เนื่องจากการเรียกเมธอดแบบวงกลม

คลิกช่องทำเครื่องหมาย -> onCheckedChanged () -> alertDataSetChanged () -> onBindViewHolder () -> set checkbox -> onChecked ...

เพียงแค่คุณแก้ไขปัญหานี้ได้โดยใส่ค่าสถานะหนึ่งรายการลงในอะแดปเตอร์

ลองสิ่งนี้

private boolean onBind;

public ViewHolder(View itemView) {
    super(itemView);
    mCheckBox = (CheckBox) itemView.findViewById(R.id.checkboxId);
    mCheckBox.setOnCheckChangeListener(this);
}

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    if(!onBind) {
        // your process when checkBox changed
        // ...

        notifyDataSetChanged();
    }
}

...

@Override
public void onBindViewHolder(YourAdapter.ViewHolder viewHolder, int position) {
    // process other views 
    // ...

    onBind = true;
    viewHolder.mCheckBox.setChecked(trueOrFalse);
    onBind = false;
}

ฉันเห็นว่ามีเหตุผล หวังว่าแพลตฟอร์มจะทำนายพฤติกรรมง่ายๆเช่นนี้และให้วิธีแก้ปัญหาแทนที่จะต้องพึ่งธง ..
อาเธอร์

ไม่สำคัญว่าคุณจะตั้งค่าผู้ฟังไว้ที่ใดตราบเท่าที่คุณไม่ได้แจ้งให้ทราบในAdapterViewObserverขณะที่onBindViewHolder()กำลังดำเนินการอยู่
Yaroslav Mytkalyk

6
ฉันชอบโซลูชันนี้stackoverflow.com/a/32373999/1771194พร้อมการปรับปรุงบางอย่างในความคิดเห็น นอกจากนี้ยังอนุญาตให้ฉันสร้าง "RadioGroup" ใน RecyclerView
Artem

ฉันจะได้รับตำแหน่งในรายการของฉันได้อย่างไร ??
filthy_wizard

2
สิ่งนี้ใช้ไม่ได้สำหรับฉันในตัวดู ยังคงได้รับข้อผิดพลาดข้อขัดข้อง ฉันต้องการเปลี่ยน vars ในรายการอาร์เรย์ ที่แปลกมาก. ไม่แน่ใจเหมือนกันว่าฉันจะแนบรายชื่อได้ที่ไหน
filthy_wizard

46

คุณสามารถรีเซ็ตฟังก่อนหน้านี้ก่อนที่จะทำการเปลี่ยนแปลงและคุณจะไม่ได้รับข้อยกเว้นนี้

private CompoundButton.OnCheckedChangeListener checkedListener = new CompoundButton.OnCheckedChangeListener() {                      
                        @Override
                        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                            //Do your stuff
                    });;

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        holder.checkbox.setOnCheckedChangeListener(null);
        holder.checkbox.setChecked(condition);
        holder.checkbox.setOnCheckedChangeListener(checkedListener);
    }

2
คำตอบที่ดี แต่จะดีกว่าที่จะไม่สร้าง Listener ในการโทรแต่ละครั้งของ onBindViewHolder ทำให้เป็นสนาม.
Artem

1
แน่นอนว่าการใช้ฟิลด์นั้นดีกว่าฉันแค่ยกตัวอย่างที่ใช้ได้ผล แต่ขอบคุณสำหรับคำเตือนฉันจะอัปเดตคำตอบ
JoniDS

1
ฉันจำเป็นต้องผูกผู้ฟังใหม่ทุกครั้งเพราะผู้ฟังต้องการตัวแปรตำแหน่งที่อัปเดตทุกครั้ง นี่เป็นคำตอบที่ดีมากดังนั้นฉันจึงไม่ต้องใช้ Handler
Rock Lee

นี่เป็นวิธีที่ดีที่สุดในการดำเนินการอย่างแน่นอนเนื่องจากไม่แนะนำให้รักษาสถานะโลกไว้ซึ่งคำตอบที่ยอมรับ ( stackoverflow.com/a/31069171/882251 ) แนะนำ
Darwind

ง่ายที่สุด !! ขอบคุณ !!
DalveerSinghDaiya

39

การใช้Handlerเพื่อเพิ่มรายการและการโทรnotify...()จากสิ่งนี้Handlerช่วยแก้ปัญหาให้ฉันได้


3
นั่นเป็นคำตอบที่ถูกต้องคุณไม่สามารถเปลี่ยนรายการในขณะที่ตั้งค่าได้ (ด้วยการเรียก onBindViewHolder) ในกรณีนี้คุณต้องโทรแจ้งเตือนเมื่อสิ้นสุดลูปปัจจุบันโดยโทร Handler.post ()
pjanecze

1
@ user1232726 หากคุณสร้าง Handler บนเธรดหลักคุณไม่จำเป็นต้องระบุ Looper (ค่าเริ่มต้นของตัววนการเรียกเธรด) ใช่นี่คือคำแนะนำของฉัน มิฉะนั้นคุณสามารถระบุ Looper ด้วยตนเองได้
cybergen

ขออภัยช่องทำเครื่องหมายของฉันไม่ถูกตรวจสอบเมื่อฉันเลื่อนลงและเลื่อนกลับขึ้นอีกครั้ง หุยฮา lol
filthy_wizard

@ user1232726 ค้นหาคำตอบหรือถามคำถามใหม่ที่อธิบายปัญหาของคุณ
cybergen

2
ฉันขอไม่แนะนำคำตอบนี้เป็นอย่างยิ่งเนื่องจากเป็นวิธีที่แฮ็กในการแก้ปัญหา ยิ่งคุณทำสิ่งนี้มากขึ้นโค้ดของคุณก็ซับซ้อนมากขึ้นในการทำความเข้าใจ อ้างอิงคำตอบของ Moonsooเพื่อทำความเข้าใจปัญหาและคำตอบของ JoniDS ในการแก้ปัญหา
Kalpesh Patel

26

ฉันไม่ทราบดี แต่ฉันก็มีปัญหาเหมือนกัน ฉันแก้ไขสิ่งนี้โดยใช้onClickListnerบนcheckbox

viewHolder.mCheckBox.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            if (model.isCheckboxBoolean()) {
                model.setCheckboxBoolean(false);
                viewHolder.mCheckBox.setChecked(false);
            } else {
                model.setCheckboxBoolean(true);
                viewHolder.mCheckBox.setChecked(true);
            }
            notifyDataSetChanged();
        }
    });

ลองใช้วิธีนี้อาจช่วยได้!


1
ใช้งานได้ดี) แต่เมื่อคลิกเท่านั้น (ถ้าฉันเลื่อนวิดเจ็ตช้า (SwitchCompat) การกระทำนี้จะพลาดนี่เป็นปัญหาเดียว
Vlad

12
protected void postAndNotifyAdapter(final Handler handler, final RecyclerView recyclerView, final RecyclerView.Adapter adapter) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (!recyclerView.isComputingLayout()) {
                    adapter.notifyDataSetChanged();
                } else {
                    postAndNotifyAdapter(handler, recyclerView, adapter);
                }
            }
        });
    }

ฉันคิดว่าคุณสามารถแจ้งอะแดปเตอร์สองครั้งได้อย่างง่ายดาย
МаксимПетлюк

8

เมื่อคุณมีข้อความผิดพลาด:

Cannot call this method while RecyclerView is computing a layout or scrolling

ง่ายๆเพียงแค่ทำสิ่งที่ทำให้เกิดข้อยกเว้นใน:

RecyclerView.post(new Runnable() {
    @Override
    public void run() {
        /** 
        ** Put Your Code here, exemple:
        **/
        notifyItemChanged(position);
    }
});

1
สิ่งนี้ได้ผลสำหรับฉัน สงสัยว่าจะมีปัญหากับโซลูชันนี้หรือไม่?
Sayooj Valsan

7

พบวิธีง่ายๆ -

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{

    private RecyclerView mRecyclerView; 

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        mRecyclerView = recyclerView;
    }

    private CompoundButton.OnCheckedChangeListener checkedChangeListener 
    = (compoundButton, b) -> {
        final int position = (int) compoundButton.getTag();
        // This class is used to make changes to child view
        final Event event = mDataset.get(position);
        // Update state of checkbox or some other computation which you require
        event.state = b;
        // we create a runnable and then notify item changed at position, this fix crash
        mRecyclerView.post(new Runnable() {
            @Override public void run() {
                notifyItemChanged(position));
            }
        });
    }
}

ที่นี่เราสร้าง runnable เพื่อแจ้งเตือนItemChangedสำหรับตำแหน่งเมื่อ Recyclerview พร้อมที่จะจัดการ


5

รายการ CheckBox ของคุณอยู่ในการเปลี่ยนแปลงที่เบิกได้เมื่อคุณโทรnotifyDataSetChanged();ดังนั้นข้อยกเว้นนี้จะเกิดขึ้น ลองโทรnotifyDataSetChanged();ในโพสต์ของคุณดู ตัวอย่างเช่น:

buttonView.post(new Runnable() {
                    @Override
                    public void run() {
                        notifyDataSetChanged();
                    }
                });

4

ตอนแรกฉันคิดว่าคำตอบของ Moonsoo ( คำตอบที่ยอมรับ) จะไม่เหมาะกับฉันเพราะฉันไม่สามารถเริ่มต้นไฟล์setOnCheckedChangeListener()ในตัวสร้าง ViewHolder ได้เนื่องจากฉันต้องผูกมันทุกครั้งเพื่อให้ได้รับตัวแปรตำแหน่งที่อัปเดต แต่ฉันใช้เวลานานกว่าจะรู้ตัวว่าเขาพูดอะไร

นี่คือตัวอย่างของ "วิธีการเรียกแบบวงกลม" ที่เขาพูดถึง:

public void onBindViewHolder(final ViewHolder holder, final int position) {
    SwitchCompat mySwitch = (SwitchCompat) view.findViewById(R.id.switch);
    mySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                       if (isChecked) {
                           data.delete(position);
                           notifyItemRemoved(position);
                           //This will call onBindViewHolder, but we can't do that when we are already in onBindViewHolder!
                           notifyItemRangeChanged(position, data.size());
                       }
                   }
            });
    //Set the switch to how it previously was.
    mySwitch.setChecked(savedSwitchState); //If the saved state was "true", then this will trigger the infinite loop.
}

ปัญหาเดียวของสิ่งนี้คือเมื่อเราต้องการเริ่มต้นสวิตช์เพื่อเปิดหรือปิด (จากสถานะที่บันทึกไว้ในอดีตเป็นต้น) มันกำลังเรียกผู้ฟังซึ่งอาจเรียกnofityItemRangeChangedซึ่งเรียกonBindViewHolderอีกครั้ง คุณไม่สามารถโทรหาได้onBindViewHolderเมื่อเข้ามาแล้วonBindViewHolder] เนื่องจากคุณไม่สามารถโทรได้notifyItemRangeChangedหากคุณอยู่ระหว่างแจ้งว่ามีการเปลี่ยนแปลงช่วงรายการ แต่ฉันต้องการอัปเดต UI เพื่อแสดงหรือปิดเท่านั้นไม่ต้องการให้ทริกเกอร์อะไรเลย

นี่คือวิธีแก้ปัญหาที่ฉันได้เรียนรู้จากคำตอบของ JoniDSที่จะป้องกันการวนซ้ำที่ไม่สิ้นสุด ตราบใดที่เราตั้งค่า Listener เป็น "null" ก่อนที่เราจะตั้งค่า Checked มันก็จะอัปเดต UI โดยไม่เรียกผู้ฟังหลีกเลี่ยงการวนซ้ำที่ไม่มีที่สิ้นสุด จากนั้นเราสามารถตั้งค่าฟังหลังจากนั้นได้

รหัสของ JoniDS:

holder.checkbox.setOnCheckedChangeListener(null);
holder.checkbox.setChecked(condition);
holder.checkbox.setOnCheckedChangeListener(checkedListener);

โซลูชันแบบเต็มสำหรับตัวอย่างของฉัน:

public void onBindViewHolder(final ViewHolder holder, final int position) {
    SwitchCompat mySwitch = (SwitchCompat) view.findViewById(R.id.switch);

    //Set it to null to erase an existing listener from a recycled view.
    mySwitch.setOnCheckedChangeListener(null);

    //Set the switch to how it previously was without triggering the listener.
    mySwitch.setChecked(savedSwitchState); //If the saved state was "true", then this will trigger the infinite loop.

    //Set the listener now.
    mySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked) {
                data.delete(position);
                notifyItemRemoved(position);
                //This will call onBindViewHolder, but we can't do that when we are already in onBindViewHolder!
                notifyItemRangeChanged(position, data.size());
            }
        }
    });
}

คุณควรหลีกเลี่ยงการเริ่มต้น OnCheckedChangeListener ซ้ำแล้วซ้ำอีกใน onBindViewHolder (ต้องใช้ GC น้อยกว่าด้วยวิธีนี้) สิ่งนี้ควรจะถูกเรียกใน onCreateViewHolder และคุณจะได้รับตำแหน่งโดยการโทรหา holder.getAdapterPosition ()
นักพัฒนา Android

4

ทำไมไม่ตรวจสอบRecyclerView.isComputingLayout()รัฐดังนี้?

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{

    private RecyclerView mRecyclerView; 

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        mRecyclerView = recyclerView;
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int position) {

        viewHolder.getCheckbox().setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (mRecyclerView != null && !mRecyclerView.isComputingLayout()) {
                    notifyDataSetChanged();
                }
            }
        });
    }
}

2

ในขณะที่รายการถูกผูกไว้โดยตัวจัดการโครงร่างเป็นไปได้มากว่าคุณกำลังตั้งค่าสถานะที่เลือกไว้ของช่องทำเครื่องหมายของคุณซึ่งจะทำให้เกิดการเรียกกลับ

แน่นอนว่านี่เป็นการคาดเดาเนื่องจากคุณไม่ได้เผยแพร่การติดตามสแต็กแบบเต็ม

คุณไม่สามารถเปลี่ยนเนื้อหาของอะแด็ปเตอร์ได้ในขณะที่ RV กำลังคำนวณเค้าโครงใหม่ คุณสามารถหลีกเลี่ยงได้โดยไม่เรียกใช้ alertDataSetChanged หากสถานะการตรวจสอบของรายการเท่ากับค่าที่ส่งในการเรียกกลับ (ซึ่งจะเป็นกรณีนี้หากการโทรcheckbox.setCheckedเรียกใช้การโทรกลับ)


ขอบคุณ @yigit! ปัญหาของฉันไม่ได้เกี่ยวข้องกับช่องทำเครื่องหมาย แต่เป็นสถานการณ์ที่ซับซ้อนกว่าที่ฉันต้องแจ้งรายการอื่นในอะแดปเตอร์ แต่ฉันได้รับความผิดพลาดที่คล้ายกัน ฉันอัปเดตตรรกะการแจ้งเตือนให้อัปเดตเฉพาะเมื่อข้อมูลมีการเปลี่ยนแปลงจริงและแก้ไขข้อขัดข้องของฉันได้ ดังนั้นกฎใหม่ของฉันกับ RecyclerViews: อย่าแจ้งว่ามีอะไรเปลี่ยนแปลงเมื่อไม่มีอะไรเปลี่ยนแปลง ขอบคุณมากสำหรับคำตอบนี้!
CodyEngel

2

ใช้ onClickListner ในช่องทำเครื่องหมายแทน OnCheckedChangeListener จะช่วยแก้ปัญหาได้

viewHolder.myCheckBox.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            if (viewHolder.myCheckBox.isChecked()) {
                // Do something when checkbox is checked
            } else {
                // Do something when checkbox is unchecked                
            }
            notifyDataSetChanged();
        }
    });



0

ฉันพบปัญหานี้แน่นอน! หลังจากคำตอบของ Moonsoo ไม่ได้ลอยเรือของฉันจริงๆฉันก็ยุ่งเล็กน้อยและพบวิธีแก้ปัญหาที่เหมาะกับฉัน

ขั้นแรกนี่คือรหัสบางส่วนของฉัน:

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

    final Event event = mDataset.get(position);

    //
    //  .......
    //

    holder.mSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            event.setActive(isChecked);
            try {
                notifyItemChanged(position);
            } catch (Exception e) {
                Log.e("onCheckChanged", e.getMessage());
            }
        }
    });

คุณจะสังเกตเห็นว่าฉันกำลังแจ้งอแด็ปเตอร์โดยเฉพาะสำหรับตำแหน่งที่ฉันเปลี่ยนแทนที่จะเป็นชุดข้อมูลทั้งหมดเหมือนที่คุณทำ ดังที่กล่าวไว้แม้ว่าฉันจะไม่สามารถรับประกันได้ว่าสิ่งนี้จะใช้ได้กับคุณ แต่ฉันก็แก้ปัญหาได้ด้วยการตัดnotifyItemChanged()สายของฉันในบล็อก try / catch นี่เป็นเพียงข้อยกเว้น แต่ยังอนุญาตให้อะแดปเตอร์ของฉันลงทะเบียนการเปลี่ยนแปลงสถานะและอัปเดตการแสดงผล!

หวังว่านี่จะช่วยใครสักคน!

แก้ไข: ฉันยอมรับว่านี่อาจไม่ใช่วิธีที่เหมาะสม / เป็นผู้ใหญ่ในการจัดการปัญหา แต่เนื่องจากดูเหมือนว่าจะไม่ก่อให้เกิดปัญหาใด ๆ โดยปล่อยให้ข้อยกเว้นไม่สามารถจัดการได้ฉันคิดว่าฉันจะแบ่งปันในกรณีที่มันดี เพียงพอสำหรับคนอื่น


0

สิ่งนี้เกิดขึ้นเนื่องจากคุณอาจตั้งค่า 'ผู้ฟัง' ก่อนที่คุณจะกำหนดค่าสำหรับแถวนั้นซึ่งทำให้ผู้ฟังถูกทริกเกอร์เมื่อคุณ 'กำหนดค่า' สำหรับช่องทำเครื่องหมาย

สิ่งที่คุณต้องทำคือ:

@Override
public void onBindViewHolder(YourAdapter.ViewHolder viewHolder, int position) {
   viewHolder.mCheckBox.setOnCheckedChangeListener(null);
   viewHolder.mCheckBox.setChecked(trueOrFalse);
   viewHolder.setOnCheckedChangeListener(yourCheckedChangeListener);
}

0
        @Override
        public void onBindViewHolder(final MyViewHolder holder, final int position) {
            holder.textStudentName.setText(getStudentList.get(position).getName());
            holder.rbSelect.setChecked(getStudentList.get(position).isSelected());
            holder.rbSelect.setTag(position); // This line is important.
            holder.rbSelect.setOnClickListener(onStateChangedListener(holder.rbSelect, position));

        }

        @Override
        public int getItemCount() {
            return getStudentList.size();
        }
        private View.OnClickListener onStateChangedListener(final RadioButton checkBox, final int position) {
            return new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (checkBox.isChecked()) {
                        for (int i = 0; i < getStudentList.size(); i++) {

                            getStudentList.get(i).setSelected(false);

                        }
                        getStudentList.get(position).setSelected(checkBox.isChecked());

                        notifyDataSetChanged();
                    } else {

                    }

                }
            };
        }

0

เพียงแค่ใช้isPressed()วิธีการCompoundButtonในการonCheckedChanged(CompoundButton compoundButton, boolean isChecked)
เช่น

public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {   
                      ... //your functionality    
                            if(compoundButton.isPressed()){
                                notifyDataSetChanged();
                            }
                        }  });

0

ฉันมีปัญหาเดียวกันกับการใช้ Checkbox และ RadioButton แทนที่notifyDataSetChanged()ด้วยการnotifyItemChanged(position)ทำงาน ฉันเพิ่มฟิลด์บูลีนisCheckedในโมเดลข้อมูล แล้วฉันจะปรับปรุงค่าบูลีนและผมเรียกว่าonCheckedChangedListener notifyItemChanged(adapterPosition)นี่อาจไม่ใช่วิธีที่ดีที่สุด แต่ได้ผลสำหรับฉัน ค่าบูลีนใช้สำหรับตรวจสอบว่ามีการตรวจสอบรายการหรือไม่


0

ส่วนใหญ่มันเกิดขึ้น beacause notifydatasetchangedโทรonCheckedchangedกรณีที่มีการทำเครื่องหมายในช่องและในกรณีที่อีกครั้งมีnotifydatasetchanged

ในการแก้ปัญหาคุณสามารถตรวจสอบว่าช่องทำเครื่องหมายถูกเลือกโดยโปรแกรมหรือผู้ใช้กด มีวิธีการคือกดสำหรับมัน

ดังนั้นให้ห่อรหัส listner ทั้งหมดไว้ข้างในคือวิธีกด และมันเสร็จแล้ว

 holder.mBinding.cbAnnual.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {

                if(compoundButton.isPressed()) {


                       //your code
                        notifyDataSetChanged();   

            }
        });

0

ฉันประสบปัญหานี้มาหลายชั่วโมงแล้วและนี่คือวิธีที่คุณจะแก้ไขได้ แต่ก่อนที่คุณจะเริ่มมีเงื่อนไขบางประการในการแก้ปัญหานี้

คลาสรุ่น

public class SelectUserModel {

    private String userName;
    private String UserId;
    private Boolean isSelected;


    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserId() {
        return UserId;
    }

    public void setUserId(String userId) {
        UserId = userId;
    }

    public Boolean getSelected() {
        return isSelected;
    }

    public void setSelected(Boolean selected) {
        isSelected = selected;
    }
}

CHECKBOX ใน ADAPTER CLASS

CheckBox cb;

ผู้สร้างคลาสอะแดปเตอร์และรายชื่อรุ่น

private List<SelectUserModel> userList;

public StudentListAdapter(List<SelectUserModel> userList) {
        this.userList = userList;

        for (int i = 0; i < this.userList.size(); i++) {
            this.userList.get(i).setSelected(false);
        }
    }

ONBINDVIEW [โปรดใช้ onclick แทน onCheckChange]

public void onBindViewHolder(@NonNull final StudentListAdapter.ViewHolder holder, int position) {
    holder.cb.setChecked(user.getSelected());
    holder.cb.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            int pos = (int) view.getTag();
            Log.d(TAG, "onClick: " + pos);
            for (int i = 0; i < userList.size(); i++) {
                if (i == pos) {
                    userList.get(i).setSelected(true);
// an interface to listen to callbacks
                    clickListener.onStudentItemClicked(userList.get(i));
                } else {
                    userList.get(i).setSelected(false);
                }
            }
            notifyDataSetChanged();
        }
    });

}


-1

สำหรับฉันปัญหาเกิดขึ้นเมื่อฉันออกจาก EditText โดย Done, Back หรือสัมผัสอินพุตภายนอก สิ่งนี้ทำให้อัปเดตโมเดลด้วยข้อความอินพุตจากนั้นรีเฟรชมุมมองรีไซเคิลผ่านการสังเกตข้อมูลสด

ปัญหาคือเคอร์เซอร์ / โฟกัสยังคงอยู่ใน EditText

เมื่อฉันลบโฟกัสโดยใช้:

editText.clearFocus() 

วิธีการแจ้งข้อมูลที่เปลี่ยนไปของมุมมองผู้รีไซเคิลหยุดแสดงข้อผิดพลาดนี้

ฉันคิดว่านี่เป็นหนึ่งในเหตุผล / วิธีแก้ปัญหานี้ที่เป็นไปได้ เป็นไปได้ว่าข้อยกเว้นนี้สามารถแก้ไขได้ด้วยวิธีอื่นเนื่องจากอาจเกิดจากสาเหตุที่แตกต่างกันโดยสิ้นเชิง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.