Как сделать рабочий флажок внутри ListView (в котором есть элементы из базы данных sqlite)

#java #android #sqlite #android-layout

#java #Android #sqlite #android-макет

Вопрос:

Я пытаюсь сделать рабочий флажок внутри ListView. Макет просто main.xml который показывает несколько row.xml когда новая информация добавляется в базу данных sqlite. Я могу сделать рабочий флажок в main.xml , но я не знаю, как сделать рабочий флажок внутри row.xml .

AndroidSQLite.java (показывает main.xml , и row.xml внутри него)

      public class AndroidSQLite extends Activity {
     (...)

    checkBoxMain = (CheckBox)findViewById(R.id.checkboxmain1);

    listContent = (ListView)findViewById(R.id.contentlist);

    mySQLiteAdapter = new SQLiteAdapter(this);
    mySQLiteAdapter.openToWrite();

    cursor = mySQLiteAdapter.queueAll();
    String[] from = new String[]{SQLiteAdapter._id, 
    SQLiteAdapter.KEY_NAME,
                            SQLiteAdapter.KEY_QUANTITY, 
    SQLiteAdapter.KEY_CHECKED};
    int[] to = new int[]{R.id.id, R.id.name, R.id.quantity, 
    R.id.checkboxmain};
    cursorAdapter =
            new SimpleCursorAdapter(this, R.layout.row, cursor, from, 
    to);
    listContent.setAdapter(cursorAdapter);

    listContent.setOnItemClickListener(listContentOnItemClickListener);


    buttonAdd.setOnClickListener(buttonAddOnClickListener);

    checkBoxMain.setOnClickListener(onCheckboxClicked);

}
  

Флажок OnClickListener (AndroidSQLite.java )

 CheckBox.OnClickListener onCheckboxClicked
        = new CheckBox.OnClickListener() {

    public void onClick(View v) {
        CheckBox checkBoxMain = (CheckBox) 
 findViewById(R.id.checkboxmain1);
        boolean checked = checkBoxMain.isChecked();
        if (checked) {
            Boolean data1 = checkBoxMain.isChecked();
            mySQLiteAdapter.insertChecked(data1);
            updateList();
        }
    }

};
  

ListView OnItemClickListener (AndroidSQLite.java )

   private ListView.OnItemClickListener listContentOnItemClickListener
        = new ListView.OnItemClickListener(){

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int 
    position,
                            long id) {


        Cursor cursor = (Cursor) parent.getItemAtPosition(position);
        final int item_id = 
   cursor.getInt(cursor.getColumnIndex(SQLiteAdapter._id));
        String item_name = 
   cursor.getString(cursor.getColumnIndex(SQLiteAdapter.KEY_NAME));
        String item_quantity = 
 cursor.getString(cursor.getColumnIndex(SQLiteAdapter.KEY_QUANTITY));

        AlertDialog.Builder myDialog
                = new AlertDialog.Builder(AndroidSQLite.this);
      // when item in row.xml is clicked alertdialog is shown
      // code of AlertDialog

 myDialog.show();
    }};
  

onDestroy и updateList() (AndroidSQLite.java )

 @Override
protected void onDestroy() {
    // TODO Auto-generated method stub
    super.onDestroy();
    mySQLiteAdapter.close();
}



private void updateList(){
    cursor.requery();
}
  

main.xml

    <?xml version="1.0" encoding="utf-8"?>
   <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <TextView
        android:id="@ id/panelup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="LIST SQ1"
        />

    <ListView
        android:id="@ id/contentlist"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_below="@id/panelup"
        android:layout_above="@id/paneldown"/>
    <CheckBox
        android:id="@ id/checkboxmain1"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <LinearLayout
        android:id="@ id/paneldown"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true">
        <EditText
            android:id="@ id/name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            />
        <EditText
            android:id="@ id/quantity"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            />
        <Spinner
            android:id="@ id/mu"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:entries="@array/mu_values"
            android:layout_weight="2"
          />
        <Button
            android:id="@ id/add"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:text=" "
            />
    </LinearLayout>
    </RelativeLayout>
  

row.xml

  <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@ id/layoutmain"
    >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:padding="2dip"
        android:text="M"/>
    <TextView
        android:id="@ id/id"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:padding="2dip"
        android:paddingRight="10dip"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:padding="2dip"
        android:paddingRight="10dip"
        android:text="-" />
    <TextView
        android:id="@ id/name"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:padding="2dip"/>
</LinearLayout>
<TextView
    android:id="@ id/quantity"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="2dip"/>
<CheckBox
    android:id="@ id/checkboxmain2"
    android:focusable="false"
    android:focusableInTouchMode="false"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
</LinearLayout>
  

(checkboxmain2 из row.xml установите android: focusable и android:focusableInTouchMode на «false», потому что, если это не false, ListView OnItemClickListener не работает)

SQLiteAdapter.java

 public class SQLiteAdapter {
(...)
public SQLiteAdapter openToWrite() throws android.database.SQLException {
    sqLiteHelper = new SQLiteHelper(context, MYDATABASE_NAME, null, 
MYDATABASE_VERSION);
    sqLiteDatabase = sqLiteHelper.getWritableDatabase();
    return this;
}


public void close(){
    sqLiteHelper.close();
}

public long insertChecked(boolean data1){

    ContentValues contentValues = new ContentValues();
    contentValues.put(KEY_CHECKED, data1);
    return sqLiteDatabase.insert(MYDATABASE_TABLE, null, contentValues);
}

public Cursor queueAll(){
    String[] columns = new String[]{_id, KEY_NAME, KEY_PRICE, 
KEY_QUANTITY, KEY_MU,
            KEY_PDATE, KEY_SHOP, KEY_CHECKED};
    Cursor cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns,
            null, null, null, null, null);

    return cursor;
}
  

экран

Флажок сверху, который проверяется на экране, является рабочим флажком (checkboxmain1), который добавляет «1» в базу данных

Есть ли какой-либо способ сделать ответ флажков в ListView?

Ответ №1:

Ниже приведен относительно простой способ обработки событий щелчка просмотров внутри элемента ListView.

Чтобы просто получить фактический элемент, на который был нажат, чтобы отличить его от другого элемента, вам нужен пользовательский адаптер, в данном случае пользовательский адаптер курсора, в котором вы можете установить для тега представления соответствующее значение (идентификатор).

В сочетании с этим вы используете атрибут onClick, чтобы указать метод, который будет вызываться при нажатии на view (флажок), который определен в Activity.

Ниже приведен рабочий пример, основанный на вашем коде. Он использует более простой и гибкий метод для управления ListView, т.е. manageListView

Обратите внимание, что часть вашего кода была опущена (закомментирована) для удобства.

Код

row.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@ id/layoutmain"
        >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:padding="2dip"
            android:text="M"/>
        <TextView
            android:id="@ id/id"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:padding="2dip"
            android:paddingRight="10dip"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:padding="2dip"
            android:paddingRight="10dip"
            android:text="-" />
        <TextView
            android:id="@ id/name"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:padding="2dip"/>
    </LinearLayout>
    <TextView
        android:id="@ id/quantity"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="2dip"/>
    <CheckBox
        android:id="@ id/checkboxmain2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="ListViewCheckBoxHanlder"/>
</LinearLayout>
  
  • Обратите внимание на изменения, внесенные в флажок

activity_main.xml

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <TextView
        android:id="@ id/panelup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="LIST SQ1"
        />
    <ListView
        android:id="@ id/contentlist"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_below="@id/panelup"
        android:layout_above="@id/paneldown"/>
    <CheckBox
        android:id="@ id/checkboxmain1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <LinearLayout
        android:id="@ id/paneldown"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true">
        <EditText
            android:id="@ id/name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            />
        <EditText
            android:id="@ id/quantity"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            />
        <Spinner
            android:id="@ id/mu"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:entries="@array/mu_values"
            android:layout_weight="2"
            />
        <Button
            android:id="@ id/add"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:text=" "
            />
    </LinearLayout>
</RelativeLayout>
  

AndroidSQLite.java

 public class AndroidSQLite extends AppCompatActivity {

    CheckBox checkBoxMain;
    ListView listContent;
    Button buttonAdd;
    Cursor cursor;
    SQLiteAdapter mySQLiteAdapter;
    //SimpleCursorAdapter cursorAdapter; //<<<<<<<<<< NOT USED ANYMORE
    MyCursorAdapter myadapter; //<<<<<<<<<< Use a custom adapter that sets the tag of the checkbox to the respective id

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        checkBoxMain = (CheckBox)findViewById(R.id.checkboxmain1);
        listContent = (ListView)findViewById(R.id.contentlist);
        mySQLiteAdapter = new SQLiteAdapter(this);
        mySQLiteAdapter.openToWrite();
        manageListView(); //<<<<<<<<<< ADDED

        /* !!!!!!!!! COMMENTED OUT
        cursor = mySQLiteAdapter.queueAll();
        String[] from = new String[]{SQLiteAdapter._id,
                SQLiteAdapter.KEY_NAME,
                SQLiteAdapter.KEY_QUANTITY,
                SQLiteAdapter.KEY_CHECKED};
        int[] to = new int[]{R.id.id, R.id.name, R.id.quantity,
                R.id.checkboxmain2};
        cursorAdapter =
                new SimpleCursorAdapter(this, R.layout.row, cursor, from,
                        to,0);
        listContent.setAdapter(cursorAdapter);

        listContent.setOnItemClickListener(listContentOnItemClickListener);
        */
        //buttonAdd.setOnClickListener(buttonAddOnClickListener); //<<<<<<<<<<< you want this back in
    }

    //<<<<<<<<<< ADDED >>>>>>>>>>
    @Override
    protected void onResume() {
        super.onResume();
        manageListView(); //Refresh the List when resuming e.g. returning from another activity
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        cursor.close(); //<<<<<<<<<< SHOULD ALWAYS CLOSE CURSOR
        mySQLiteAdapter.close();
    }

    //<<<<<<<<<< NO LONGER USED >>>>>>>>>>
    private void updateList(){
        cursor = mySQLiteAdapter.queueAll();
        myadapter.swapCursor(cursor);
    }

    //<<<<<<<< NOTE NOT USED but you'd want this to be used
    CheckBox.OnClickListener onCheckboxClicked
            = new CheckBox.OnClickListener() {

        public void onClick(View v) {
            CheckBox checkBoxMain = (CheckBox)
                    findViewById(R.id.checkboxmain1);
            boolean checked = checkBoxMain.isChecked();
            if (checked) {
                Boolean data1 = checkBoxMain.isChecked();
                mySQLiteAdapter.insertChecked(data1);
                manageListView(); //<<<<<<<<<< refresh the ListView
            }
        }
    };

    //<<<<<<<<<<NOT USED>>>>>>>>>>
    private ListView.OnItemClickListener listContentOnItemClickListener
            = new ListView.OnItemClickListener(){

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int
                position,
                                long id) {
            Cursor cursor = (Cursor) parent.getItemAtPosition(position);
            final int item_id =
                    cursor.getInt(cursor.getColumnIndex(SQLiteAdapter._id));
            String item_name =
                    cursor.getString(cursor.getColumnIndex(SQLiteAdapter.KEY_NAME));
            String item_quantity =
                    cursor.getString(cursor.getColumnIndex(SQLiteAdapter.KEY_QUANTITY));

            AlertDialog.Builder myDialog
                    = new AlertDialog.Builder(AndroidSQLite.this);
            // when item in row.xml is clicked alertdialog is shown
            // code of AlertDialog
            myDialog.show();
            updateList();
        }
    };

    /**<<<<<<<<<< ADDED >>>>>>>>>>>
     * Manage the ListView building from new or refreshing the data
     */
    private void manageListView() {
        cursor = mySQLiteAdapter.queueAll(); // get the source data (cursor) for the listview
        if (myadapter == null) {
            myadapter = new MyCursorAdapter(this,cursor);
            listContent.setAdapter(myadapter);
        } else {
            myadapter.swapCursor(cursor);
        }
    }

    /**<<<<<<<<<< ADDED >>>>>>>>>>
     * Handle the CheckBox being clicked,
     * NOTE set in the layout
     * @param v     The View
     */
    public void ListViewCheckBoxHanlder(View v) {
        CheckBox cb = v.findViewById(R.id.checkboxmain2);
        Toast.makeText(this, "You clicked the CheckBox for ID "   (String) cb.getTag(), Toast.LENGTH_SHORT).show();
        int checked = 0;
        if (cb.isChecked()) {
            checked = 1;
        }
        long id = Long.valueOf((String) cb.getTag());
        mySQLiteAdapter.updateChecked(id,checked);
        manageListView();
    }
}
  
  • Обратите внимание, что некоторые закомментированные коды были заменены, некоторые были закомментированы для удобства.

MyCursorAdapter.java

 public class MyCursorAdapter extends CursorAdapter {


    public MyCursorAdapter(Context context, Cursor c) {
        super(context, c, true);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = super.getView(position, convertView, parent);
        return v;
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        return LayoutInflater.from(context).inflate(R.layout.row,parent,false);
    }

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

        //Note Cursor will be positioned appropriately
        TextView name = (TextView) view.findViewById(R.id.name);
        TextView id = (TextView) view.findViewById(R.id.id);
        TextView quantity = (TextView) view.findViewById(R.id.quantity);
        CheckBox cb = (CheckBox) view.findViewById(R.id.checkboxmain2);

        name.setText(cursor.getString(cursor.getColumnIndex(SQLiteAdapter.KEY_NAME)));
        id.setText(cursor.getString(cursor.getColumnIndex(SQLiteAdapter._id)));
        quantity.setText(cursor.getString(cursor.getColumnIndex(SQLiteAdapter.KEY_QUANTITY)));
        cb.setChecked(cursor.getInt(cursor.getColumnIndex(SQLiteAdapter.KEY_CHECKED)) > 0);
        cb.setTag(cursor.getString(cursor.getColumnIndex(SQLiteAdapter._id))); //<<<<<<<<<< SET TAG to the ID
    }
} 
  
  • Обратите внимание, что выше приведен новый класс.

SQliteAdapter.java

 public class SQLiteAdapter {

    SQLiteDatabase sqLiteDatabase;
    SQLiteHelper sqLiteHelper;
    Context context;

    public static final String KEY_CHECKED = "checked";
    public static final String _id = BaseColumns._ID;
    public static final String KEY_NAME = "name";
    public static final String KEY_QUANTITY = "quantity";
    public static final String KEY_PRICE = "price";
    public static final String KEY_MU = "mu";
    public static final String KEY_PDATE = "pdate";
    public static final String KEY_SHOP = "shop";

    public SQLiteAdapter(Context context) {
        this.context = context;
        openToWrite();
    }

    public SQLiteAdapter openToWrite() throws android.database.SQLException {
        sqLiteHelper = new SQLiteHelper(context, MYDATABASE_NAME, null,
                MYDATABASE_VERSION);
        sqLiteDatabase = sqLiteHelper.getWritableDatabase();
        return this;
    }


    public void close() {
        sqLiteHelper.close();
    }

    public long insertChecked(boolean data1) {

        ContentValues contentValues = new ContentValues();
        contentValues.put(KEY_CHECKED, data1);
        return sqLiteDatabase.insert(MYDATABASE_TABLE, null, contentValues);
    }

    public int updateChecked(long id,int check) {
        ContentValues cv = new ContentValues();
        cv.put(KEY_CHECKED,check);
        String whereclause = _id   "=?";
        String[] whereargs = new String[]{String.valueOf(id)};
        return sqLiteDatabase.update(MYDATABASE_TABLE,cv,whereclause,whereargs);
    }

    public Cursor queueAll() {
        String[] columns = new String[]{_id, KEY_NAME, KEY_PRICE,
                KEY_QUANTITY, KEY_MU,
                KEY_PDATE, KEY_SHOP, KEY_CHECKED};
        Cursor cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns,
                null, null, null, null, null);
        return cursor;
    }
}
  
  • Обратите внимание, что это может быть по-другому, оно было создано для тестирования.

SQLiteHelper.java

 public class SQLiteHelper extends SQLiteOpenHelper {

    public static final String MYDATABASE_NAME = "mydatabase";
    public static final int  MYDATABASE_VERSION = 1;
    public static final String MYDATABASE_TABLE = "mytable";

    SQLiteDatabase mDB;

    public SQLiteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory,int version) {
        super(context, name, factory, version);
        mDB = this.getWritableDatabase();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String crt_tbl_sql = "CREATE TABLE IF NOT EXISTS "   MYDATABASE_TABLE   "("  
                SQLiteAdapter._id   " INTEGER PRIMARY KEY, "  
                SQLiteAdapter.KEY_NAME   " TEXT, "  
                SQLiteAdapter.KEY_SHOP   " TEXT, "  
                SQLiteAdapter.KEY_PDATE   " TEXT, "  
                SQLiteAdapter.KEY_PRICE   " REAL, "  
                SQLiteAdapter.KEY_QUANTITY   " INTEGER, "  
                SQLiteAdapter.KEY_MU   " TEXT, "  
                SQLiteAdapter.KEY_CHECKED   " INTEGER DEFAULT 0"  
                ")";
        db.execSQL(crt_tbl_sql);
        addSomeTestingData(db,10);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    private long addRow(String name, String shop, String pdate, double price, int quantity, String mu, SQLiteDatabase db) {
        ContentValues cv = new ContentValues();
        cv.put(SQLiteAdapter.KEY_NAME,name);
        cv.put(SQLiteAdapter.KEY_SHOP,shop);
        cv.put(SQLiteAdapter.KEY_PDATE,pdate);
        cv.put(SQLiteAdapter.KEY_PRICE,price);
        cv.put(SQLiteAdapter.KEY_QUANTITY,quantity);
        cv.put(SQLiteAdapter.KEY_MU,mu);
        return db.insert(MYDATABASE_TABLE,null,cv);
    }

    private void addSomeTestingData(SQLiteDatabase db, int number_to_add) {

        for (int i = 0; i < number_to_add;i  ) {
            String suffix = String.valueOf(i);
            String day_in_month = suffix;
            if (i < 10) {
                day_in_month = "0"   day_in_month;
            }
            addRow(
                    "Test"   suffix,
                    "Shop"   suffix,
                    "2019-01-"   day_in_month,
                    10.5   new Double(i * 3),
                    i * 4,
                    "mu"   suffix,
                    db
            );
        }
    }
}
  
  • Обратите внимание, что это может быть по-другому, оно было создано для тестирования.

Результат

Ниже приведен снимок экрана, сделанный после нажатия нескольких флажков, чтобы отображался тост :-

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

И скриншот после перезапуска приложения (показывающий, что состояние сохранено, т. Е. База данных обновлена в соответствии с флажками) :-

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

Комментарии:

1. Я записал ваши изменения в свой код, и это работает! Большое спасибо вам! Вечером я изучу эти изменения, чтобы понять больше кода 🙂 . Хорошего дня!