Как исправить курсор, который # 2 записи вместо # 1 (# 3 вместо # 2 и т. Д.)? - PullRequest
0 голосов
/ 02 мая 2019

Layout - это просто main.xml, который показывает несколько строк.xml при добавлении новой информации в базу данных sqlite. При нажатии кнопки отображается AlertDialog с данными. Проблема в том, что когда я нажимаю кнопку в строке, AlertDialog получает данные из следующей записи (следующей строки) в базе данных (когда я нажимаю первую кнопку, AD берет вторую запись и т. Д.), А не из позиции, в которой находится кнопка. Я установил метку для кнопки, и сообщение о тосте показывает хороший идентификатор при нажатии.

MyCursorAdapter.java

(...)

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

TextView name = (TextView) view.findViewById(R.id.name);
TextView id = (TextView) view.findViewById(R.id.id);
TextView quantity = (TextView) view.findViewById(R.id.quantity);
TextView mu = (TextView) view.findViewById(R.id.mu);
Button bt = (Button) view.findViewById(R.id.rowalertdialog);
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)));
mu.setText(cursor.getString(cursor.getColumnIndex(SQLiteAdapter.KEY_MU)));
bt.setTag(cursor.getString(cursor.getColumnIndex(SQLiteAdapter._id)));
cb.setChecked(cursor.getInt(cursor.getColumnIndex(SQLiteAdapter.KEY_CHECKED)) > 0);
cb.setTag(cursor.getString(cursor.getColumnIndex(SQLiteAdapter._id)));
}

AndroidSQLite.java

(...)

private void manageListView() {
cursor = mySQLiteAdapter.queueAll();
if(myadapter == null){
    myadapter = new MyCursorAdapter(this,cursor);
    listContent.setAdapter(myadapter);
}else {
    myadapter.swapCursor(cursor);
}
}

onClick для кнопки

 public void ListViewButtonHandler(View v){
Button bt = v.findViewById(R.id.rowalertdialog);
Toast.makeText(this, "You clicked the Button for ID " + (String)bt.getTag(), Toast.LENGTH_SHORT).show();

int id = Integer.valueOf((String) bt.getTag());
ListView parent = (ListView)findViewById(R.id.contentlist);
Cursor cursor = (Cursor) parent.getItemAtPosition(id);


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);

myDialog.setTitle("Delete/Edit?");

TextView dialogTxt_id = new TextView(AndroidSQLite.this);
LayoutParams dialogTxt_idLayoutParams
        = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
dialogTxt_id.setLayoutParams(dialogTxt_idLayoutParams);
dialogTxt_id.setText("#" + String.valueOf(item_id));

final EditText dialogC1_id = new EditText(AndroidSQLite.this);
LayoutParams dialogC1_idLayoutParams
        = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
dialogC1_id.setLayoutParams(dialogC1_idLayoutParams);
dialogC1_id.setText(item_name);

final EditText dialogC2_id = new EditText(AndroidSQLite.this);
LayoutParams dialogC2_idLayoutParams
        = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
dialogC2_id.setLayoutParams(dialogC2_idLayoutParams);
dialogC2_id.setText(item_quantity);

LinearLayout layout = new LinearLayout(AndroidSQLite.this);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(dialogTxt_id);
layout.addView(dialogC1_id);
layout.addView(dialogC2_id);
myDialog.setView(layout);

myDialog.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
    // do something when the button is clicked
    public void onClick(DialogInterface arg0, int arg1) {
        mySQLiteAdapter.delete_byID(item_id);
        updateList();
        //manageListView();
    }
});

myDialog.setNeutralButton("Update", new DialogInterface.OnClickListener() {
    // do something when the button is clicked
    public void onClick(DialogInterface arg0, int arg1) {
        String value1 = dialogC1_id.getText().toString();
        String value2 = dialogC2_id.getText().toString();
        mySQLiteAdapter.update_byID(item_id, value1, value2);
        updateList();
        //manageListView();
    }
});

myDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
    // do something when the button is clicked
    public void onClick(DialogInterface arg0, int arg1) {

    }
});
manageListView();
myDialog.show();
}

Я думаю, что проблема в:

int id = Integer.valueOf((String) bt.getTag());
ListView parent = (ListView)findViewById(R.id.contentlist);
Cursor cursor = (Cursor) parent.getItemAtPosition(id);

Но я не знаю, как это решить. Я не знаю, почему он берет "следующую" запись.

EDIT Я сделал вторые (альтернативные) изменения в коде, и теперь, когда я нажимаю кнопку, активность возвращается к предыдущему экрану (основная активность). Logcat показывает:

  FATAL EXCEPTION: main
 Process: com.sjkdev.androidsqlite, PID: 14453
 java.lang.IllegalStateException: Could not execute method for android:onClick
    at 

android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:390)
at android.view.View.performClick(View.java:5646)
at android.view.View$PerformClick.run(View.java:22459)
at android.os.Handler.handleCallback(Handler.java:761)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:156)
at 
android.app.ActivityThread.main(ActivityThread.java:6523)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:941)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:831)
 Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385)
at android.view.View.performClick(View.java:5646) 
at android.view.View$PerformClick.run(View.java:22459) 
at android.os.Handler.handleCallback(Handler.java:761) 
at android.os.Handler.dispatchMessage(Handler.java:98) 
at android.os.Looper.loop(Looper.java:156) 
at android.app.ActivityThread.main(ActivityThread.java:6523) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:941) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:831) 
 Caused by: android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 1
at android.database.AbstractCursor.checkPosition(AbstractCursor.java:460)
at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
at android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:68)
at com.sjkdev.androidsqlite.AndroidSQLite.ListViewButtonHandler(AndroidSQLite.java:307)

Ответы [ 2 ]

2 голосов
/ 03 мая 2019

Рабочий пример

Вот пример приложения, основанный на вашем предыдущем вопросе, а также на этом вопросе.

Однако

  • обработка нажатия кнопки, обрабатывается без использования макета onCLick (как закодировано в XML), но задается в bindView пользовательском методе CursorAdapter ( MyCursorAdapter.java ).

  • демонстрирует 3 способа получения идентификатора, связанного с кнопкой

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

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

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

Результирующее приложение выглядит так: -

enter image description here

  • A указывает, что строки были удалены (т.е. строки с идентификаторами 5-7 не существуют)
  • B показывает строки, которые были обновлены (т.е. обновление было добавлено (если обновление обновляет, то строка была обновлена ​​дважды))
  • C показывает добавленные строки.

Если нажать кнопку РЕДАКТИРОВАТЬ ИЛИ УДАЛИТЬ , появится диалоговое окно, например, : -

enter image description here

  • Нажатие кнопки ОТМЕНА возвращает из диалогового окна ничего не делая.
  • Нажатие на УДАЛИТЬ удалит соответствующую строку (как подробно описано в сообщении диалога).
  • При нажатии кнопки РЕДАКТИРОВАТЬ имя редактируется путем добавления обновленного значения (редактирование уже редактируемой строки добавит дальнейшее обновление)
    • очевидно, что это, вероятно, не будет обязательным действием, это просто для демонстрации.

Код

activity_main.xml

: -

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"/>
    <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:inputType="number"
            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>
</LinearLayout>

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:visibility="gone"/>
    <Button
        android:id="@+id/editordelete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="EDIT or DELETE"/>
</LinearLayout>
  • Примечание. CheckBox скрыт

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 onConfigure(SQLiteDatabase db) {
        super.onConfigure(db);
        db.setForeignKeyConstraintsEnabled(true);
    }

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

    }

    public 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
            );
        }
    }
}

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;
    }

    public Cursor queueOneById(long id) {
        String whereclause = _id + "=?";
        String[] whereargs = new String[]{String.valueOf(id)};
        String[] columns = new String[]{_id, KEY_NAME, KEY_PRICE,
                KEY_QUANTITY, KEY_MU,
                KEY_PDATE, KEY_SHOP, KEY_CHECKED};
        return sqLiteDatabase.query(MYDATABASE_TABLE,columns,whereclause,whereargs,
                null,null,null);

    }

    public int delete(long id) {
        String whereclause = SQLiteAdapter._id + "=?";
        String[] wherargs = new String[]{String.valueOf(id)};
        return sqLiteDatabase.delete(MYDATABASE_TABLE,whereclause,wherargs);
    }

    public long updateById(long id, String column_to_change, String newvalue) {
        ContentValues cv = new ContentValues();
        cv.put(column_to_change,newvalue);
        String whereclause = SQLiteAdapter._id + "=?";
        String[] whereargs = new String[]{String.valueOf(id)};
        return sqLiteDatabase.update(MYDATABASE_TABLE,cv,whereclause,whereargs);
    }
}
  • Некоторые методы были добавлены

MyCursorAdapter.java

public class MyCursorAdapter extends CursorAdapter {

    SQLiteAdapter sqliteAdapter;
    MyCursorAdapter thisCursorAdapter;


    public MyCursorAdapter(Context context, Cursor c) {

        super(context, c, true);
        sqliteAdapter = new SQLiteAdapter(context);
        thisCursorAdapter = this;
    }

    @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, final 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);
        Button eod = (Button) view.findViewById(R.id.editordelete);

        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
        eod.setTag(cursor.getString(cursor.getColumnIndex(SQLiteAdapter._id)));
        // dynamically add the listeners as opposed to coding onCLick in layout XML
        eod.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                // get the id from the id TextView, within the view hierarchy rather than from the buttons tag
                // NOTE assumes the Button's parent is a LinearLayout (for simplicity)

                // This in theory is the recommended way rather than setting the tag
                LinearLayout ll = (LinearLayout) v.getParent();
                TextView id = ll.findViewById(R.id.id), name = ll.findViewById(R.id.name);
                final long item_id_fromview = Long.valueOf(id.getText().toString());
                final String item_name = name.getText().toString();

                // get the id from the tag
                long item_id_fromtag = Long.valueOf(v.getTag().toString());
                // get the if from the cursor that is the source of the Listview, it should be positioned accordingly
                long item_id_fromcursor = cursor.getLong(cursor.getColumnIndex(SQLiteAdapter._id));

                // Show both
                Toast.makeText(v.getContext(),
                        "The id (from the view hierarchy) is " + String.valueOf(item_id_fromview) +
                                " or (from the tag) is " + String.valueOf(item_id_fromtag) +
                                " or (from the cursor) is" + String.valueOf(item_id_fromcursor)
                        , Toast.LENGTH_SHORT).show();
                AlertDialog.Builder mydialog = new AlertDialog.Builder(v.getContext());
                mydialog.setMessage("EDIT or DELETE Row:- ID: " + String.valueOf(item_id_fromview) + "Name: " + item_name);
                mydialog.setPositiveButton("DELETE", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        sqliteAdapter.delete(item_id_fromview);
                        refreshList();
                    }
                });
                mydialog.setNeutralButton("EDIT", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        sqliteAdapter.updateById(item_id_fromview,SQLiteAdapter.KEY_NAME,item_name + " Updated");
                        refreshList();
                    }
                });
                mydialog.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                    }
                });
                mydialog.show();
            }
        });
    }
    private void refreshList() {
        thisCursorAdapter.swapCursor(sqliteAdapter.queueAll());
        thisCursorAdapter.notifyDataSetChanged();
    }
}
  • Посмотрите, как установлен onCLickListener при привязке представления
  • Посмотрите 3 различных способа получить id
  • См. Метод refreshList, аналогичный методу ManageListView, используемому в действии AndroidSQLite.

AndroidSQlite.java (активность)

public class AndroidSQLite extends AppCompatActivity {

    ListView listContent;
    Button buttonAdd;
    Cursor cursor;
    SQLiteAdapter mySQLiteAdapter;
    EditText name, quantity;
    Spinner mu;
    //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);
        listContent = (ListView) findViewById(R.id.contentlist);
        name = (EditText) findViewById(R.id.name);
        quantity = (EditText) findViewById(R.id.quantity);
        buttonAdd = (Button) findViewById(R.id.add);
        mu = (Spinner) findViewById(R.id.mu);
        handleAddButton();
        mySQLiteAdapter = new SQLiteAdapter(this);
        mySQLiteAdapter.openToWrite();
        manageListView(); //<<<<<<<<<< ADDED
    }

    //<<<<<<<<<< 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();
    }

    private void handleAddButton() {
        buttonAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if ((name.getText().toString()).length() < 1) {
                    Toast.makeText(v.getContext(),"Name cannot be empty",Toast.LENGTH_SHORT).show();
                    name.requestFocus();
                    return;
                }
                if ((quantity.getText().toString()).length() < 1) {
                    Toast.makeText(v.getContext(),"Quantity cannot be empty",Toast.LENGTH_SHORT).show();
                    quantity.requestFocus();
                    return;
                }
                mySQLiteAdapter.sqLiteHelper.addRow(
                        name.getText().toString(),
                        // Arbritary values for testing
                        "2019-01-01",
                        "The Shop",
                        100.33,
                        Integer.valueOf(quantity.getText().toString()),
                        mu.getSelectedItem().toString(),
                        mySQLiteAdapter.sqLiteDatabase
                );
                manageListView();
            }
        });

    }

    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);
        }
    }
}
1 голос
/ 02 мая 2019

Cursor cursor = (Cursor) parent.getItemAtPosition(id);получит элемент в соответствии с его положением в списке, но вы используете идентификатор (как извлечено из тега кнопки) в качестве его позиции.Это будет редко, если когда-либо будет правильным.

Первая позиция в списке - 0, первый идентификатор - 1 (при условии, что строки не были удалены, и вы не устанавливаете идентификатор вручную), и, следовательно, симптомыВы сообщаете.

Если строки были удалены, то каждый отсутствующий идентификатор может увеличить разницу между идентификатором и положением.Если строки отсортированы в любом другом порядке, кроме id, то позиции v id могут быть выходом.Если предложение where исключает строки, то снова идентификаторы и позиции будут различаться.

Простой факт: вы не можете полагаться на какие-либо отношения между id и позицией в списке.

Что вы можете сделатьэто использовать идентификатор из тега, чтобы запросить базу данных для извлечения конкретной строки.Запрос будет таким же, как запрос, используемый для получения курсора для списка, за исключением того, что он будет использовать 3-й (SQLiteAdapter._id + "=?") и 4-й параметры (new String[]{String.valueOf(id)}) (если используется удобный метод запроса).

  • Примечание исправлено (отсутствует S добавлено в QLiteAdapter) с момента комментария.

Amemded

Я попытался добавить код, как я написалв последнем комментарии, но это неправильно.Я не знаю, как реализовать ваши изменения.-

Ваш код может быть: -

public void ListViewButtonHandler(View v){
    Button bt = v.findViewById(R.id.rowalertdialog);
    Toast.makeText(this, "You clicked the Button for ID " + (String)bt.getTag(), Toast.LENGTH_SHORT).show(); //TODO not needed

    int id = Integer.valueOf((String) bt.getTag());
    ListView parent = (ListView)findViewById(R.id.contentlist); //<<<<<<<<<< NOT NEEDED (I think)


    String whereclause = SQLiteAdapter._id _ "=?"; //<<<<<<<<<< ADDED
    String[] whereargs = new String[]{bt.getTag()}; //<<<<<<<<<< ADDED
    Cursor cursor = mySQLiteAdapter.getWitableDatabase().query(SQLiteAdapter.MYDATABASE_TABLE,null,whereclause,whereargs,null,null,null); //<<<<<<<<<< ADDED
    //Cursor cursor = (Cursor) parent.getItemAtPosition(id); //<<<<<<<<<< REMOVED/COMMENTED OUT
    //<<<<<<<<<<< ADDED to move to the extracted row, will toast if no such row
    if (!cursor.moveToFirst) {
        Toast.makeText(this, "Unable to retrieve row for ID " + (String)bt.getTag(), Toast.LENGTH_SHORT).show();
        return;
    }

    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))
    cursor.close(); //<<<<<<<<<< ADDED should always close a cursor when done with it
    .......... the rest of the code
  • Обратите внимание на комментарии

  • Примечание вам может потребоваться изменить SQLiteAdapter.MYDATABASE_TABLE на соответствующее значение.

  • Обратите внимание, что приведенный выше код является принципиальным кодом, он не был протестирован или запущен и поэтому может иметь некоторые ошибки

Альтернатива

Если вы добавили следующий метод (на основе предыдущего вопроса) в SQLiteAdapter.java: -

public Cursor queueOneById(long id) {
    String whereclause = _id + "=?";
    String[] whereargs = new String[]{String.valueOf(id)}; 
    String[] columns = new String[]{_id, KEY_NAME, KEY_PRICE,
            KEY_QUANTITY, KEY_MU,
            KEY_PDATE, KEY_SHOP, KEY_CHECKED};
    return sqLiteDatabase.query(MYDATABASE_TABLE,columns,whereclause,whereargs,
            null,null,null);

}

Затем вы можете изменить

    Cursor cursor = mySQLiteAdapter.getWitableDatabase().query(SQLiteAdapter.MYDATABASE_TABLE,null,whereclause,whereargs,null,null,null);

на

    Cursor cursor = mySQLiteAdapter.queueOneById(id);
  • Обратите внимание, что для этого все еще требуются другие изменения, указанные выше.То есть вам нужно: -

    if (! Cursor.moveToFirst) {Toast.makeText (this, "Невозможно получить строку для идентификатора" + (String) bt.getTag (), Toast.LENGTH_SHORT) .show();вернуть;}

  • без вышеуказанного кода.Курсор будет в позиции -1 (перед первой строкой).Таким образом, cursor.moveToFirst необходимо расположить на извлеченной строке (должна быть только одна строка).Если строк нет, moveToFirst вернет false (перемещение не может быть выполнено), и будет выдан тост, а затем вернется метод onClick.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...