SwitchCompat onClickListener เรียกทุกปุ่มในกลุ่ม

ฉันกำลังสร้าง ListView ของสวิตช์ที่เติมข้อมูลแบบไดนามิกจากฐานข้อมูล ฉันต้องตรวจสอบว่าได้เลือกอย่างน้อยหนึ่งรายการ และเปิด/ปิดปุ่มดำเนินการต่อ ฉันกำลังจัดเก็บค่าของสวิตช์ไว้ใน HashMap เพื่อให้สามารถตรวจสอบได้อย่างง่ายดายว่ามันมีค่าจริงหรือไม่

สวิตช์ถูกสร้างขึ้นใน CursorAdapter และฉันได้ลองทั้งการตั้งค่า OnClickListener และ OnCheckedChangeListener แล้ว ดูเหมือนว่าเมื่อมีการคลิกรายการ Listener จะเริ่มทำงานสำหรับทุกปุ่มในรายการ และค่าที่ฉันจัดเก็บไว้ใน HashMap จะถูกเขียนทับด้วยสถานะที่เลือกของปุ่มที่อยู่ถัดจากรายการ

class LanguageInstallAdapter extends CursorAdapter {

    private final String LOG_TAG = LanguageInstallAdapter.class.getSimpleName();
    public HashMap<String,Boolean> mDBValues = new HashMap<String,Boolean>(); //original DB values
    public HashMap<String,Boolean> mChangedValues = new HashMap<String,Boolean>();//anything changed
    private HashMap<String,Boolean> mAllCurrentValues= new HashMap<String,Boolean>(); //complete current
    private View mRootView;

    public static class ViewHolder {
        public final TextView nameView;
        public final SwitchCompat installSwitch;

        public ViewHolder(View view) {
            nameView = (TextView) view.findViewById(R.id.language_textview);
            installSwitch = (SwitchCompat) view.findViewById(R.id.installed_switch);
        }
    }

    public LanguageInstallAdapter(Context context, Cursor c, int flags, View root) {
        super(context, c, flags);
        mRootView = root;
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View view = LayoutInflater.from(context).inflate(R.layout.list_item_install_language, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);
        view.setTag(viewHolder);
        return view;
    }

    @Override
    public void bindView(View view, final Context context, final Cursor cursor) {
        ViewHolder viewHolder = (ViewHolder) view.getTag();
        String languageId = cursor.getString(LanguageInstallFragment.COL_ID);
        String name = cursor.getString(LanguageInstallFragment.COL_NAME);
        boolean langInstalled = cursor.getInt(LanguageInstallFragment.COL_INSTALLED)>0; //convert DB 1 or 0 to java boolean
        mDBValues.put(languageId, langInstalled);
        mAllCurrentValues.put(languageId, langInstalled);
        viewHolder.nameView.setText(name);
        viewHolder.installSwitch.setChecked(langInstalled);
        viewHolder.installSwitch.setTag(languageId);
        viewHolder.installSwitch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                CompoundButton button = (CompoundButton) v;
                String buttonLang= (String) button.getTag();
                mChangedValues.put(buttonLang, button.isChecked());
                mAllCurrentValues.put(buttonLang, button.isChecked());
                setSubmitButton();
            }
        });
    }

    public void setSubmitButton(){

        for (Map.Entry<String,Boolean> entry : mAllCurrentValues.entrySet()) {
            Log.d(LOG_TAG, "Hashmap: " + entry.getKey() + " " + entry.getValue());
        }

        if(mAllCurrentValues.containsValue(true)) {
            mRootView.findViewById(R.id.submit_button).setEnabled(true);
            mRootView.findViewById(R.id.lang_prompt).setVisibility(View.GONE);
        } else {
            mRootView.findViewById(R.id.submit_button).setEnabled(false);
            mRootView.findViewById(R.id.lang_prompt).setVisibility(View.VISIBLE);
        }
    }
}

บันทึกเอาต์พุตจากลำดับการเลือก:

Initial state (none selected)
09-07 20:21:29.445  ﹕ Hashmap: 4 false
09-07 20:21:29.445  ﹕ Hashmap: 2 false
09-07 20:21:29.445  ﹕ Hashmap: 3 false

Select 2 (1 selected)
09-07 20:22:42.096  ﹕ Hashmap: 4 false
09-07 20:22:42.096  ﹕ Hashmap: 2 true
09-07 20:22:42.096  ﹕ Hashmap: 3 false

Select 3 (2 selected)
09-07 20:23:28.192  ﹕ Hashmap: 4 false
09-07 20:23:28.192  ﹕ Hashmap: 2 false
09-07 20:23:28.192  ﹕ Hashmap: 3 true

Select 4 (3 selected)
09-07 20:23:43.608  ﹕ Hashmap: 4 true
09-07 20:23:43.608  ﹕ Hashmap: 2 false
09-07 20:23:43.608  ﹕ Hashmap: 3 true

Unselect 2 (2 selected)
09-07 20:23:58.507  ﹕ Hashmap: 4 true
09-07 20:23:58.507  ﹕ Hashmap: 2 false
09-07 20:23:58.507  ﹕ Hashmap: 3 false

Unselect 3 (1 selected)
09-07 20:24:13.942  ﹕ Hashmap: 4 false
09-07 20:24:13.942  ﹕ Hashmap: 2 false
09-07 20:24:13.942  ﹕ Hashmap: 3 false

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


person asorenson    schedule 07.09.2015    source แหล่งที่มา


คำตอบ (1)


แทนที่บรรทัดนี้

mAllCurrentValues.put(languageId, langInstalled);

กับ

if (mAllCurrentValues.contains(languageId)) {
    langInstalled = mAllCurrentValues.get(languageId);        
} else {
    mAllCurrentValues.put(languageId, langInstalled);
}
person Derek Fung    schedule 07.09.2015
comment
ฉันเรียก setSubmitButton() ที่ส่วนท้ายของ bindView() โดยมีแนวคิดในการใช้สิ่งนั้นเพื่อตั้งค่าปุ่มส่งเมื่อสร้างรายการ ฉันรู้ว่ามันถูกเรียกว่าซ้ำซ้อน แต่ฉันไม่สามารถหาที่อื่นที่จะเรียกมันได้เมื่อรายการถูกสร้างขึ้นอย่างสมบูรณ์ ฉันพบว่า onLoadFinished() ถูกเรียกก่อนที่ bindView() จะดำเนินการสำหรับรายการ นอกเหนือจากนั้น การรับสายที่นี่ ยังคงทำงานผิดปกติ: ถ้าฉันเลือกรายการ มันจะเปิดใช้งานปุ่ม แต่หากฉันเลือกสองรายการขึ้นไป จากนั้นยกเลิกการเลือกรายการกลับไปหนึ่งรายการที่เลือก รายการนั้นจะทำงานเป็นศูนย์ถูกเลือกและการบันทึก คล้ายกับด้านบน - person asorenson; 07.09.2015
comment
โปรดอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับพฤติกรรมที่คุณคาดหวัง เช่น บันทึกที่คาดหวังคืออะไร? เมื่อดูโค้ดแล้ว onClickListener ควรตั้งค่าอย่างถูกต้อง ปัญหาน่าจะอยู่ที่อื่นใช่ไหม - person Derek Fung; 07.09.2015
comment
พฤติกรรมสุดท้ายสำหรับผู้ใช้คือปุ่มจะเปิดใช้งานเมื่อมีการเลือกอย่างน้อยหนึ่งรายการเท่านั้น เพื่อให้บรรลุเป้าหมายนี้ ฉันกำลังใส่ค่าบูลีนลงใน HashMap โดยมี languageId เป็นคีย์ ในตอนแรก ค่าจะถูกเติมจากฐานข้อมูล จากนั้นจะมีการอัปเดตทุกครั้งที่ผู้ใช้เลือกรายการ ดังนั้น ฉันคาดหวังว่าค่า HashMap จะสะท้อนถึงค่าของสวิตช์ในรายการ และเมื่อมีอย่างน้อยหนึ่งรายการอยู่ในสถานะที่เลือก ปุ่มจะถูกเปิดใช้งาน - person asorenson; 07.09.2015
comment
ไม่ ตอนนี้ใช้งานไม่ได้ ฉันได้อัปเดตการบันทึกด้านบนด้วยชุดตัวเลือกต่างๆ - person asorenson; 07.09.2015
comment
อัปเดตแล้ว โปรดตรวจสอบ ดูเหมือนว่าคุณจะรีเซ็ตบันทึกใน mAllCurrentValues ทุกๆ bindView - person Derek Fung; 07.09.2015
comment
ฉันจะทดสอบเพิ่มเติม แต่ดูเหมือนว่าจะได้ผล ฉันสับสนว่าทำไม bindView ถูกเรียกทุกครั้งที่เลือกรายการหรือไม่ หากมีการเขียนทับค่าเหล่านั้น เหตุใดจึงไม่เขียนทับค่า DB ดั้งเดิมทั้งหมดทุกครั้ง - person asorenson; 07.09.2015
comment
เมื่อคุณเลื่อนไปรอบๆ จะสามารถเรียก bindview ได้ จุดประสงค์เดิมคือเพื่อนำมุมมองกลับมาใช้ใหม่ และเหลือจำนวนมุมมองเพียงเล็กน้อยไว้ในหน่วยความจำ เช่น. คุณสามารถมี listview ได้ถึง 10,000 รายการ แต่อาจมีเพียง 4 รายการเท่านั้นที่จะแสดงบนหน้าจอ listview และ recyclerview ไม่ได้เก็บการดูทั้งหมด 10,000 รายการไว้เพื่อให้หน่วยความจำมีประสิทธิภาพ - person Derek Fung; 07.09.2015