ListView и CursorAdapter не поддерживают состояние при прокрутке

введите здесь описание изображения

У меня есть ListView, который заполнен пользовательским CursorAdapter, этот CursorAdapter имеет несколько выбираемых/действующих компонентов внутри.

Когда даже я выполняю некоторые действия в ListView и прокручиваю представление, состояния теряются.

Когда я наблюдал за logcat, я мог видеть, что код onCheckChangeListener для этих компонентов вызывается каждый раз, даже если кнопки не нажимаются. Не уверен, что не так.

public class CalendarSettinsAdapater extends CursorAdapter {

    private int myClickPosition;
    private int myCheckPosition;
    DBHelper dbHelper;
    Context classContext;
    Cursor classCursor;
    ToggleButton mtoggle;
    CheckBox mCheckBox;
    TextView mTitle;
    Button mButton;
    boolean buttonEnable = false;

    ToggleEvent toggleEvent = new ToggleEvent();
    ToggleEventListener toggleEventLis = new ToggleEventListener();

    ListView calListView;

    @SuppressWarnings("deprecation")
    public CalendarSettinsAdapater(Context context, Cursor c) {
        super(context, c);
    }

    @SuppressLint("ResourceAsColor")
    @Override
    public void bindView(View view, Context context, Cursor cursor) {

        Typeface tf = Typeface.createFromAsset(context.getAssets(),
                "fonts/Glegoo-Regular.ttf");

        calListView = (ListView) view.findViewById(R.id.calendarSettingsList);
        mTitle = (TextView) view.findViewById(R.id.calendarName);
        mtoggle = (ToggleButton) view.findViewById(R.id.silentToggle);
        mButton = (Button) view.findViewById(R.id.calendarExceptionEvents);
        mCheckBox = (CheckBox) view.findViewById(R.id.visibility);
        mtoggle.setTag(cursor.getPosition());
        mButton.setTag(cursor.getPosition());
        mCheckBox.setTag(cursor.getPosition());

        mTitle.setTypeface(tf);

        mTitle.setText(cursor.getString(cursor.getColumnIndex(cursor
                .getColumnName(1))));

        mTitle.setTextColor(Color.WHITE);

        classContext = context;
        classCursor = cursor;

        View v = view.findViewById(R.id.circleShape);
        final GradientDrawable rectCal = (GradientDrawable) v.getBackground();

        int key = Integer.parseInt(cursor.getString(cursor
                .getColumnIndex(cursor.getColumnName(0))));

        rectCal.setColor(cursor.getInt(cursor.getColumnIndex(cursor
                .getColumnName(4))));



        mCheckBox
                .setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

                    public void onCheckedChanged(CompoundButton buttonView,
                            boolean isChecked) {

                        int position = (Integer) buttonView.getTag();
                        myCheckPosition = position;
                        if (isChecked) {
                            updateDbToShow(classContext, classCursor);
                        } else {
                            updateDbToGreyed(classContext, classCursor);
                        }

                    }

                });


        mtoggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView,
                    boolean isChecked) {
                final int position = (Integer) buttonView.getTag();
                myClickPosition = position;
                if (isChecked) {
                    updateDbToHandle(classContext, classCursor);
                } else {
                    updateDbToIgnore(classContext, classCursor);
                }
            }
        });



        setProperToggleButtonStatus(classContext, classCursor, mtoggle, mButton);

        setProperCheckBoxStatus(classContext, classCursor, mCheckBox, mTitle);

    }



    private void setProperCheckBoxStatus(Context context, Cursor cursor,
            CheckBox mcheckBox, TextView mTitle) {
        String calVisible = cursor.getString(cursor.getColumnIndex(cursor
                .getColumnName(5)));
        if (calVisible.equalsIgnoreCase("1")) {
            mcheckBox.setChecked(true);
            mtoggle.setEnabled(true);
            if (buttonEnable == true) {
                mButton.setEnabled(true);
            } else
                mButton.setEnabled(false);
        } else {
            mcheckBox.setChecked(false);
            mtoggle.setEnabled(true);
            mButton.setEnabled(true);
        }
    }

    private void setProperToggleButtonStatus(Context context, Cursor cursor,
            ToggleButton mtoggle, Button mButton) {

        dbHelper = new DBHelper(context);
        String calState1 = cursor.getString(cursor.getColumnIndex(cursor
                .getColumnName(2)));
        int calState = Integer.parseInt(calState1);
        int expEvent = dbHelper.getExceptionEvents(cursor.getString(cursor
                .getColumnIndex(cursor.getColumnName(0))), calState);
        String buttonLabel = String.valueOf(expEvent);
        if (calState1.equalsIgnoreCase("1")) {
            mtoggle.setChecked(true);
            if (expEvent < 1) {
                mButton.setEnabled(false);
                buttonEnable = false;
            } else {
                mButton.setEnabled(true);
                buttonEnable = true;
            }
            mtoggle.setEnabled(true);
            mButton.setText(buttonLabel);
            mButton.setTextColor(Color.WHITE);
            Drawable drawable = context.getResources().getDrawable(
                    R.drawable.ic_custom_ringer);
            drawable.setBounds(0, 0,
                    (int) (drawable.getIntrinsicWidth() * 0.40),
                    (int) (drawable.getIntrinsicHeight() * 0.40));
            mButton.setCompoundDrawables(drawable, null, null, null);
        } else {
            mtoggle.setChecked(false);
            if (expEvent < 1) {
                mButton.setEnabled(false);
                buttonEnable = false;
            } else {
                mButton.setEnabled(true);
                buttonEnable = true;
            }
            mtoggle.setEnabled(true);
            mButton.setText(buttonLabel);
            mButton.setTextColor(Color.WHITE);
            mButton.setCompoundDrawablesWithIntrinsicBounds(
                    R.drawable.ic_custom_silent, 0, 0, 0);
            Drawable drawable = context.getResources().getDrawable(
                    R.drawable.ic_custom_silent);
            drawable.setBounds(0, 0,
                    (int) (drawable.getIntrinsicWidth() * 0.40),
                    (int) (drawable.getIntrinsicHeight() * 0.40));
            mButton.setCompoundDrawables(drawable, null, null, null);
        }
    }

    private void updateDbToGreyed(Context context, Cursor cursor) {
        //update database
    }

    private void updateDbToShow(Context context, Cursor cursor) {
        //update database
    }

    protected void updateDbToHandle(Context context, Cursor cursor) {

        //update database
    }

    protected void updateDbToIgnore(Context context, Cursor cursor) {

        //update database
    }

    @SuppressWarnings("static-access")
    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        classContext = context;
        classCursor = cursor;
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.calendar_settings_item, null);

        calListView = (ListView) view.findViewById(R.id.calendarSettingsList);
        mTitle = (TextView) view.findViewById(R.id.calendarName);
        mtoggle = (ToggleButton) view.findViewById(R.id.silentToggle);
        mButton = (Button) view.findViewById(R.id.calendarExceptionEvents);
        mCheckBox = (CheckBox) view.findViewById(R.id.visibility);

        setProperCheckBoxStatus(classContext, classCursor, mCheckBox, mTitle);
        setProperToggleButtonStatus(classContext, classCursor, mtoggle, mButton);
        return view;
    }


    private OnClickListener mCheckBoxListener = new OnClickListener() {

        @Override
        public void onClick(View v) {
            final int position = (Integer) v.getTag();
            myCheckPosition = position;
            if (mCheckBox.isChecked()) {
                updateDbToShow(classContext, classCursor);
            } else {
                updateDbToGreyed(classContext, classCursor);
            }

        }
    };

    private OnClickListener mToggleClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            final int position = (Integer) v.getTag();
            myClickPosition = position;
            if (mtoggle.isChecked()) {
                updateDbToHandle(classContext, classCursor);
            } else {
                updateDbToIgnore(classContext, classCursor);
            }
        }
    };

}][2]

person Bala Sivagnanam    schedule 18.12.2014    source источник


Ответы (2)


Вы должны использовать концепцию ViewHolder для того же, инициализировать все компоненты представления только тогда, когда представление равно нулю,

подобно

View vi = convertView; // trying to reuse a recycled view
final ViewHolder holder;// = null;
final Item row_pos = rowItem.get(position);
if (vi == null) {
    // The view is not a recycled one: we have to inflate
    vi = mLayoutInflater.inflate(R.layout.menu_item_list_row, parent,
            false);
    holder = new ViewHolder();
    holder.txtTitle = (TextView) vi.findViewById(R.id.title);
    holder.txtPrice = (TextView) vi.findViewById(R.id.txtPrice);
    holder.edtQty = (EditText) vi.findViewById(R.id.edtQty);
    holder.edtQty.setInputType(InputType.TYPE_CLASS_NUMBER);
    vi.setTag(holder);
    // setting the image resource and title

} else {
    // View recycled !
    // no need to inflate
    // no need to findViews by id
    holder = (ViewHolder) vi.getTag();
}

return vi;
person Binit Singh    schedule 18.12.2014
comment
Я использую CursorAdapter, поэтому у нас есть только методы newView и bindView, поэтому я не получу доступ к convertView.. не знаю, как перерабатывать, только когда он равен нулю. Я думаю, что он уже повторно использует автоматически. stackoverflow.com/questions/12223293/ - person Bala Sivagnanam; 02.01.2015

Попробуйте добавить это в свой флажок в файле xml

 android:button="@null"
 android:focusable="false"
 android:focusableInTouchMode="false"

Вам необходимо контролировать изменение представления, проверяя тег макета и сохраняя состояние объекта, т.е. CheckBox.

 mCheckBox.setOnCheckedChangeListener(null);

Я использовал следующий метод. Я надеюсь, что это будет полезно.

@SuppressLint("InflateParams")
    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View v = convertView;
        ViewHolder holder = null;
        if (v == null) {
            LayoutInflater vi = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.listview_items, null);
            holder = new ViewHolder();
            holder.text_title = (TextView)v.findViewById(R.id.txt_exp_title);
            holder.text_description = (TextView)v.findViewById(R.id.txt_exp_desc);
            holder.icon = (ImageView)v.findViewById(R.id.img_exp_image);
            holder.star = (CheckBox)v.findViewById(R.id.img_exp_bookmark_selected);
            v.setTag(holder);
        } else {
            holder = (ViewHolder) v.getTag();
            holder.star.setOnCheckedChangeListener(null);
        }

        final POJOExponatListe o = filtered.get(position);
        if (o != null) {

            if (holder.text_title != null)
                holder.text_title.setText(o.getTitle());
            if (holder.text_description != null)
                holder.text_description.setText(o.getDescription());
            if (holder.icon != null)
                new AQuery(holder.icon).image(o.getImageUrl());
            Log.e(" Get VIEw ADaPTER", " " + o.getPosition());
            if (holder.star != null)
                holder.star.setChecked(o.getPosition());
            holder.star
                    .setOnCheckedChangeListener(new OnCheckedChangeListener() {

                        @Override
                        public void onCheckedChanged(CompoundButton buttonView,
                                boolean isChecked) {
                            if (isChecked) {
                                System.out.println(position + "  " + o.getID()
                                        + "--- :)");
                                dbHelper.toggleExponatBookmark(o.getID(),
                                        "true");
                                o.setPosition(true);

                            } else {
                                dbHelper.toggleExponatBookmark(o.getID(),
                                        "false");
                                o.setPosition(false);
                            }
                        }
                    });
        }

        return v;
    }
person Umesh Moradiya    schedule 18.12.2014
comment
Вы можете объяснить немного больше? Вы хотите сказать, что я должен поддерживать ArrayList или что-то в этом роде всякий раз, когда в элементы пользовательского интерфейса вносятся какие-либо изменения? - person Bala Sivagnanam; 02.01.2015
comment
Да, это хороший способ контролировать элементы списка. У вас будет больше возможностей для настройки с помощью адаптера пользовательского списка. Я бы посоветовал вам использовать его один раз, и вы также можете решить свою проблему. - person Umesh Moradiya; 03.01.2015
comment
Прости. если я правильно понимаю. Вы хотите сказать, что я должен использовать адаптер пользовательского списка, а не CursorAdapter? мой список уже пользовательский, и я расширяю CursorAdapter для этого - person Bala Sivagnanam; 04.01.2015