#android #listview #checkbox
Чекбоксы при уходе за экран, теряют свои положения при возвращении. Вот тут - SimpleCursorAdapter - фильтр для курсора есть весь код (мой вопрос). Как реализовать метод для сохранения булевых значений? Неужели вместо курсора в адаптер мне нужно отправлять массив булевых значений? А как взятие данных через курсор в методе bindView()? Ведь курсор я уберу, а он нужен. Mетод для получения данных с БД private void getProductList() { String filter = "list=" + intValue; final Cursor cursor = mSqLiteDatabase.query("products", new String[] {DatabaseProductHelper.PRODUCT_ID, DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT, DatabaseProductHelper.PRODUCT_LIST, DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE}, null, null, null, null, null) ; final Cursor cursorc = mSqLiteDatabase.query("products", new String[] {DatabaseProductHelper.PRODUCT_ID, DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT, DatabaseProductHelper.PRODUCT_LIST, DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE}, filter, null, null, null, null) ; final ArrayListarrTblNames = new ArrayList (); if (cursor.moveToFirst()) { while ( !cursor.isAfterLast() ) { if(cursor.getInt(cursor.getColumnIndex("list"))==intValue) { arrTblNames.add(cursor.getString(cursor.getColumnIndex("name"))); } cursor.moveToNext(); } String[] from = {DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT, DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE}; int[] to = {R.id.ColMemberID, R.id.ColName, R.id.count_tv, R.id.chb_products}; adapter = new InteractiveArrayAdapter(ListBuilder.this, R.layout.row, cursorc, from, to ); //lv_products.setAdapter(adapter); } if(!arrTblNames.isEmpty()){ empty_bd_layout.setAlpha(0); lv_products.setAdapter(adapter); } else{ empty_bd_layout.setAlpha(255); } } И сам адаптер public class InteractiveArrayAdapter extends SimpleCursorAdapter { private int layout; private boolean checked[]; public InteractiveArrayAdapter(Context _context, int _layout, Cursor _cursor, String[] _from, int[] _to) { super(_context, _layout, _cursor, _from, _to); layout = _layout; int counts = _cursor.getCount(); checked = new boolean[counts]; for (int i = 0; i < counts; i++){ int checkMarker = _cursor.getInt(_cursor.getColumnIndex("complete")); checked[i] = checkMarker == 1; } } @Override public void bindView(View view, Context _context, Cursor _cursor) { String prod_name = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_NAME)); String prod_count = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COUNT)); String prod_type = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_TYPE)); // int prod_complete = _cursor.getInt(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COMPLETE)); TextView name_prod_tv = (TextView)view.findViewById(R.id.ColMemberID); TextView count_prod_tv = (TextView)view.findViewById(R.id.ColName); TextView type_prod_tv = (TextView)view.findViewById(R.id.count_tv); CheckBox chb = (CheckBox)view.findViewById(R.id.chb_products); chb.setFocusable(false); chb.setClickable(false); name_prod_tv.setText(prod_name); count_prod_tv.setText(prod_count); type_prod_tv.setText(prod_type); chb.setChecked(checked[_cursor.getPosition()]); } @Override public View newView(Context _context, Cursor _cursor, ViewGroup _parent) { LayoutInflater inflater = (LayoutInflater)_context.getSystemService(_context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(layout, _parent, false); return view; } public void setChecked(int position){ // инвертируем значение при обработке клика этим методом checked[position]=!checked[position]; } } LogCat FATAL EXCEPTION: main 05-09 07:18:29.529 1468 1468 E AndroidRuntime Process: ru.diskrim.listbuy, PID: 1468 05-09 07:18:29.529 1468 1468 E AndroidRuntime java.lang.RuntimeException: Unable to start activity ComponentInfo{ru.diskrim.listbuy/ru.diskrim.listbuy.ListBuilder}: android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 4 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.app.ActivityThread.access$800(ActivityThread.java:151) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.os.Handler.dispatchMessage(Handler.java:102) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.os.Looper.loop(Looper.java:135) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.app.ActivityThread.main(ActivityThread.java:5254) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at java.lang.reflect.Method.invoke(Native Method) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at java.lang.reflect.Method.invoke(Method.java:372) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:697) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:117) 05-09 07:18:29.529 1468 1468 E AndroidRuntime Caused by: android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 4 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.database.AbstractCursor.checkPosition(AbstractCursor.java:426) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:68) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at ru.diskrim.listbuy.ListBuilder$InteractiveArrayAdapter.(ListBuilder.java:245) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at ru.diskrim.listbuy.ListBuilder.getProductList(ListBuilder.java:209) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at ru.diskrim.listbuy.ListBuilder.onCreate(ListBuilder.java:184) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.app.Activity.performCreate(Activity.java:6033) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106) 05-09 07:18:29.529 1468 1468 E AndroidRuntime at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278) 05-09 07:18:29.529 1468 1468 E AndroidRuntime ... 11 more
Ответы
Ответ 1
Решение мало чем отличается от этого ответа, с той разницей, что вам нужно обрабатывать клики из активити, а не слушателем в адаптере. Поскольку мы не можем изменять значения в курсоре, а только читать их оттуда, для запоминания текущего состояния чекбоксов требуется создать локальное хранилище. В адаптер вам нужно передавать данные, которые должны быть отображены в виджете, в вашем случае это курсор с выборкой из БД. Вспомогательный массив булевых значений никуда передавать не нужно, он создается внутри адаптера. Примерная реализация может выглядеть так: private void getProductList() { // Если требуется только имя, следует и запрашивать из БД только //колонку с именем, а не все в кучу // Если требуется только записи с каким то условием, то их и надо запрашивать, // а не все в подряд, а потом выбирать нужные каким то циклом // так же эти данные включены и в курсор для адаптера и нет нужды // получать то же самое дважды // final Cursor cursor = mSqLiteDatabase.query("products", new String[] {DatabaseProductHelper.PRODUCT_ID, DatabaseProductHelper.PRODUCT_NAME,"list = ?", new String[] {""+ intValue}, null, null, null) ; //то же самое, только нужные в адаптере колонки final Cursor cursorc = mSqLiteDatabase.query("products", new String[] {DatabaseProductHelper.PRODUCT_ID,DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT, DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE}, "list = ?", new String[] {""+ intValue}, null, null, null); final ArrayListarrTblNames = new ArrayList (); // копирование данных из курсора в массив сильно упрощается, // так как у нас только нужные данные while ( cursorc.moveToNext() ) { arrTblNames.add(cursorc.getString(cursorc.getColumnIndex("name"))); } String[] from = {DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT, DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE}; int[] to = {R.id.ColMemberID, R.id.ColName, R.id.count_tv, R.id.chb_products}; adapter = new InteractiveArrayAdapter(ListBuilder.this, R.layout.row, cursorc, from, to ); //lv_products.setAdapter(adapter); } // у виджетов есть свойство Visiblity, которое управляет видимостью на // экране, зачем тут использовать прозрачность ? // я бы поменял всю логику вообще, исходя из условия ниже, // зачем получаnь и формировать данные, если они могут не понадобится if(!arrTblNames.isEmpty()){ empty_bd_layout.setAlpha(0); lv_products.setAdapter(adapter); } else{ empty_bd_layout.setAlpha(255); } } адаптер: public class InteractiveArrayAdapter extends SimpleCursorAdapter { private int layout; private boolean checked[]; public InteractiveArrayAdapter(Context _context, int _layout, Cursor _cursor, String[] _from, int[] _to) { super(_context, _layout, _cursor, _from, _to); layout = _layout; // инициализируем вспомогательный массив начальными отметками чекбоксов из курсора checked = new boolean[_cursor.getCount()]; int i = 0; while ( _cursor.moveToNext() ) { int checkMarker = _cursor.getInt(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COMPLETE)); checked[i] = (checkMarker == 1) ? true: false; i = i + 1; } // нужно вернуть указатель курсора в первоначальное положение // перед первой записью, для корректной работы адаптера _cursor.moveToPosition(-1); } @Override public void bindView(View view, Context _context, Cursor _cursor) { String prod_name = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_NAME)); String prod_count = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COUNT)); String prod_type = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_TYPE)); // эта строка здесь теперь по видимому не нужна, поскольку значения отметок // из курсора мы уже извлекли //int prod_complete = _cursor.getInt(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COMPLETE)); TextView name_prod_tv = (TextView)view.findViewById(R.id.ColMemberID); TextView count_prod_tv = (TextView)view.findViewById(R.id.ColName); TextView type_prod_tv = (TextView)view.findViewById(R.id.count_tv); CheckBox chb = (CheckBox)view.findViewById(R.id.chb_products); chb.setFocusable(false); chb.setClickable(false); name_prod_tv.setText(prod_name); count_prod_tv.setText(prod_count); type_prod_tv.setText(prod_type); // устанавливаем чекбоксы по вспомогательному массиву, а не по курсору // получаем текущую позицию курсора (и соответственно адаптера) через его метод chb.setChecked(checked[_cursor.getPosition()]); } @Override public View newView(Context _context, Cursor _cursor, ViewGroup _parent) { LayoutInflater inflater = (LayoutInflater)_context.getSystemService(_context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(layout, _parent, false); return view; } // метод для фиксации изменений отметок чекбоксов из активити public void setChecked(int position){ // инвертируем значение при обработке клика этим методом checked[position] = !checked[position]; } } запись изменений в БД по отметкам чекбоксов у вас, насколько я помню, осуществляется при обработке клика в слушателе списка, поэтому в адаптер это действие не включено, но оно должно обязательно присутствовать, иначе при выходе из списка отметки будут утеряны.
Комментариев нет:
Отправить комментарий