简体   繁体   中英

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

Layout is just main.xml which shows multiple row.xml when new information is added to sqlite database. When button is clicked AlertDialog with data is shown. The problem is that when I click button in row, AlertDialog is taking data from next record (next row) in database (when I click first button, AD is taking second record, etc.), not from the position where button is. I setTag for button and toast message is showing good ID when it's clicked.

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 for button

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

I think problem is in:

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

But I don't know how to solve it. I don't know why it's taking "next" record.

EDIT I made second (alternative) changes to code, and now when I click button activity come back to previous screen (mainactivity). Logcat shows:

  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) ; will get the item according to it's position in the list, but you are using the id (as extracted from the button's Tag) as it's position. This will rarely if ever be correct.

The first position in the list is 0, the first id will be 1 (assuming no rows have been deleted and you aren't manually setting the id) and hence the symptoms you report.

If rows have been deleted then each missing id can increase the difference between id and position. If the rows are sorted in any other order than id, then positions v id's could be way out. If a where clause excludes rows then again id's and position would vary.

Simple fact is you can't rely on any relationship between id and the position in the list.

What you could do is use the id, from the Tag, to query the database to extract the specific row. The query would be be the same as the query used to get the cursor for the list except that it would utilise the 3rd ( SQLiteAdapter._id + "=?" ) and 4th parameters ( new String[]{String.valueOf(id)} ) (if using the query convenience method).

  • Note corrected (missing S added to QLiteAdapter) since comment.

Amemded

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

Your code could be :-

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
  • Please note the comments

  • Note you may need to change SQLiteAdapter.MYDATABASE_TABLE to an appropriate value.

  • Note the above code is in-principle code, it has not been tested or run and may therefore have some errors

Alternative

If you added the following method (based upon the previous question) to 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);

}

Then you could change

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

To

    Cursor cursor = mySQLiteAdapter.queueOneById(id);
  • Note this still requires the other changes above. That is you need :-

    if (!cursor.moveToFirst) { Toast.makeText(this, "Unable to retrieve row for ID " + (String)bt.getTag(), Toast.LENGTH_SHORT).show(); return; }

  • without the above code. The cursor will be at position -1 (before the first row). So the cursor.moveToFirst is need to position to the extracted row (should only be the one row). If there are no rows the moveToFirst will return false (the move could not be done) and the Toast will be issued and then the onClick method will return.

Working Example

Here's a working Example App based upon your previous question and also this question.

However,

  • button click handling, is handled without using the layout's onCLick (as coded in the XML) but is set in the bindView method of the custom CursorAdapter ( MyCursorAdapter.java ).

  • it demonstrates 3 methods of getting the id associated with the button

    • item_id_fromcursor shows how you can get values, (this id in this case) from the Cursor that is the source of the list, which should be appropriately positioned.
    • item_id_fromtag shows how to get the id from the tag (some frown upon this technique).
    • item_id_fromview shows how to get values from the view hierarchy based upon the view passed to the button.

The handling allows rows to be deleted and updated (albeit that update is pretty rudimentary, just appends a value rather than using a customised dialog layout(you appear to have a grasp on this aspect)).

Unlike the previous answer, handling added rows (albeit with limited values) is also implemented.

The resultant App looks like :-

在此处输入图片说明

  • A indicates that rows have been deleted (ie rows with id's 5-7 don't exist)
  • B shows rows that have been updated (ie update has been appended (if update update then the row has been updated twice))
  • C shows rows that have been added.

If the EDIT OR DELETE button is clicked the dialog appears eg :-

在此处输入图片说明

  • Clicking CANCEL returns from the dialog doing nothing.
  • Clicking DELETE will delete the respective row (as detailed in the dialog's message).
  • Clicking EDIT edits the name by appending the value updated (editing an already editing row will add a further updated)
    • obviously this would probably not be the actioned required, it's just for demonstration.

The Code

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>
  • Note CheckBox has been hidden

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);
    }
}
  • Some methods have been added

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();
    }
}
  • See how the onCLickListener is set when binding a view
  • See the 3 different ways to a get the id
  • See the refreshList method similar to the ManageListView method used in the AndroidSQLite activity.

AndroidSQlite.java (the 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);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM