如何修复使用#2nd 记录而不是#1st(#3rd 而不是#2nd 等)的游标?

How to fix cursor that is taking #2nd record instead of #1st (#3rd instead of #2nd etc.)?

布局只是 main.xml,当新信息添加到 sqlite 数据库时显示多个 row.xml。单击按钮时,会显示带有数据的 AlertDialog。 问题是,当我单击行中的按钮时,AlertDialog 正在从数据库中的下一条记录(下一行)获取数据(当我单击第一个按钮时,AD 正在获取第二条记录等),而不是从按钮所在的位置。 我为按钮和 toast 消息设置了标签,当它被点击时显示正确的 ID。

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

但是我不知道怎么解决。我不知道为什么要记录 "next"。

编辑 我对代码进行了第二次(替代)更改,现在当我单击按钮 activity 时返回到上一个屏幕(主 activity)。 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)

Cursor cursor = (Cursor) parent.getItemAtPosition(id);将根据项目在列表中的位置获取项目,但您使用的是 id(从按钮的标签中提取)作为它的位置。这很少是正确的。

列表中的第一个位置是 0,第一个 ID 将是 1(假设没有删除任何行并且您没有手动设置 ID),因此您报告的症状。

如果行已被删除,那么每个丢失的 id 都会增加 id 和位置之间的差异。如果行以除 id 之外的任何其他顺序排序,则位置 v id 可能会出局。如果 where 子句排除了行,那么 id 和位置将再次发生变化。

简单的事实是您不能依赖 id 和列表中的位置之间的任何关系。

你可以做的是使用标签中的 id 来查询数据库以提取特定行。该查询与用于获取列表游标的查询相同,只是它会使用第三个 (SQLiteAdapter._id + "=?") 和第四个参数 (new String[]{String.valueOf(id)})(如果使用查询便捷方法) .

  • 注释已更正(缺少 S 添加到 QLiteAdapter)自评论以来。

修正

I tried add code as I wrote in last comment, but it's wrong. I don't know how to implement your changes. –

您的代码可以是:-

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(这个, "Unable to retrieve row for ID " + (String)bt.getTag(), Toast.LENGTH_SHORT).show(); return; }

  • 没有上面的代码。光标将位于 -1 位置(第一行之前)。所以 cursor.moveToFirst 需要定位到提取的行(应该只是一行)。如果没有行,moveToFirst 将 return false(无法完成移动)并且将发出 Toast,然后 onClick 方法将 return.

工作示例

这是一个基于您之前的问题和这个问题的工作示例应用程序。

然而,

  • 按钮点击处理,在不使用布局的 onCLick(如 XML 中编码)的情况下进行处理,但在 bindView自定义方法CursorAdapter (MyCursorAdapter.java).

  • 它演示了获取与按钮关联的 id 的 3 种方法

    • item_id_fromcursor 展示了如何从作为列表源的 Cursor 获取值(在本例中为这个 id),它应该被适当地定位.
    • item_id_fromtag 展示了如何从标签中获取 id(有些人不赞成这种技术)。
    • item_id_fromview 展示了如何根据传递给按钮的视图从视图层次结构中获取值。

该处理允许删除和更新行(尽管该更新非常初级,只是附加一个值而不是使用自定义对话框布局(您似乎已经掌握了这方面))。

与之前的答案不同,还实现了处理添加的行(尽管值有限)。

生成的 App 如下所示:-

  • A表示行已被删除(即id为5-7的行不存在)
  • B 显示已更新的行(即已附加更新(如果更新更新则该行已更新两次))
  • C 显示已添加的行。

如果单击 编辑或删除 按钮,将出现对话框,例如:-

  • 单击对话框中的取消 returns 什么都不做。
  • 单击“删除”将删除相应的行(如对话框消息中的详细信息)。
  • 单击“编辑”通过附加更新的值来编辑名称(编辑已经编辑的行将添加进一步的更新)
    • 显然这可能不是所需的操作,它只是为了演示。

代码

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
  • 查看获取 id
  • 的 3 种不同方法
  • 查看类似AndroidSQLite中使用的ManageListView方法的refreshList方法activity。

AndroidSQlite.java (activity)

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