简体   繁体   English

如何解决获取#2nd记录而不是#1st记录的光标(#3rd而不是#2nd等)?

[英]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. 布局只是main.xml,当将新信息添加到sqlite数据库时,它将显示多个row.xml。 When button is clicked AlertDialog with data is shown. 单击按钮时,将显示带有数据的AlertDialog。 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. 问题是,当我单击行中的按钮时,AlertDialog正在从数据库中的下一条记录(下一行)中获取数据(当我单击第一个按钮时,AD正在获取第二条记录等),而不是从按钮所在位置获取数据。 I setTag for button and toast message is showing good ID when it's clicked. 我为按钮设置setTag,并在单击Toast消息时显示良好的ID。

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

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). 编辑我对代码进行了第二次(替代)更改,现在,当我单击按钮活动时,返回到先前的屏幕(mainactivity)。 Logcat shows: 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) ; 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. 将根据项目在列表中的位置获取该项目,但是您使用的是id(从按钮的Tag中提取)作为位置。 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. 列表中的第一个位置是0,第一个ID将是1(假设没有删除任何行,并且您没有手动设置ID),因此报告了症状。

If rows have been deleted then each missing id can increase the difference between id and position. 如果已删除行,则每个丢失的ID都会增加ID和位置之间的差异。 If the rows are sorted in any other order than id, then positions v id's could be way out. 如果以id以外的其他顺序对行进行排序,则位置v id可能会掉线。 If a where clause excludes rows then again id's and position would vary. 如果where子句排除行,则id和位置也会再次变化。

Simple fact is you can't rely on any relationship between id and the position in the list. 一个简单的事实是,您不能依赖id与列表中位置之间的任何关系。

What you could do is use the id, from the Tag, to query the database to extract the specific row. 您可以做的是使用Tag中的ID来查询数据库以提取特定行。 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). 该查询将与用于获取列表光标的查询相同,只不过它将使用第3个( SQLiteAdapter._id + "=?" )和第4个参数( new String[]{String.valueOf(id)} )(如果使用查询便捷方法)。

  • Note corrected (missing S added to QLiteAdapter) since comment. 自注释以来,说明已更正(缺少S添加到QLiteAdapter)。

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. 请注意,您可能需要将SQLiteAdapter.MYDATABASE_TABLE更改为适当的值。

  • 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 :- 如果您将以下方法(基于上一个问题)添加到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(); 如果(!cursor.moveToFirst){Toast.makeText(this,“无法检索ID的行” +(String)bt.getTag(),Toast.LENGTH_SHORT).show(); return; 返回; } }

  • without the above code. 没有上面的代码。 The cursor will be at position -1 (before the first row). 光标将在位置-1 (第一行之前)。 So the cursor.moveToFirst is need to position to the extracted row (should only be the one row). 因此, cursor.moveToFirst需要定位到提取的行(只能是一行)。 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. 如果没有行,则moveToFirst将返回false(无法完成移动),并且将发出Toast,然后将返回onClick方法。

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 ). 按钮单击处理,无需使用布局的onCLick (如XML中的编码)即可处理,但可以在自定义CursorAdapterMyCursorAdapter.java )的bindView方法中进行设置。

  • it demonstrates 3 methods of getting the id associated with the button 它演示了获得与按钮关联的ID的3种方法

    • 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_fromcursor显示如何从作为列表源的Cursor获取值(在这种情况下,此ID),该值应适当定位。
    • item_id_fromtag shows how to get the id from the tag (some frown upon this technique). item_id_fromtag显示了如何从标签中获取ID(对此技术有些皱眉)。
    • item_id_fromview shows how to get values from the view hierarchy based upon the view passed to the button. item_id_fromview显示如何基于传递给按钮的视图从视图层次结构获取值。

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) A表示已删除行(即ID为5-7的行不存在)
  • B shows rows that have been updated (ie update has been appended (if update update then the row has been updated twice)) B显示已更新的行(即已附加更新(如果更新已更新,则该行已被更新两次))
  • C shows rows that have been added. C显示已添加的行。

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 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 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 注意CheckBox已隐藏

SQLiteHelper.java 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 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 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 查看绑定视图时如何设置onCLickListener
  • See the 3 different ways to a get the id 查看获取ID的3种不同方式
  • See the refreshList method similar to the ManageListView method used in the AndroidSQLite activity. 请参见与AndroidSQLite活动中使用的ManageListView方法类似的refreshList方法。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java 8 LocalDate:确定每月的星期几(第1,第2,第3等) - Java 8 LocalDate: Determine What Monday of the Month its (1st, 2nd, 3rd, etc) JComboBox仅在从第1到第2时才更改组件(而不是从第3到第2时) - JComboBox changes components only when going from 1st to 2nd (Not from 3rd to 2nd) 以这样的方式更新 HashMap,使第二个值变成第一个,第三个变成第二个,依此类推 - Updating a HashMap in such a way that the 2nd value becomes 1st and 3rd becomes 2nd and so on 如何通过从第1类调用第2类的方法来调用第3类的方法 - How to call a method of a 3rd class by calling the method of the 2nd class from the 1st class 当第一个 API 和第二个 API 在测试环境中工作时,如何模拟第三个 API 响应 - How to mock 3rd API response when 1st API and 2nd API is working on test environment Android Studio:2个XML文件,但App正在启动第二个XML文件,而不是第一个 - Android Studio: 2 XML Files, but App is starting 2nd XML-file instead of 1st one 关于第一个init()和第二个init() - regarding 1st init() and 2nd init() 检查第一个 if 条件,然后检查第二个 - Checking 1st if condition and then 2nd 如何从第二活动到第一活动获取数据 - How to get data from 2nd Activity to 1st Activity 如何将代码从第二类添加到第一类 - How to add code from 2nd class to 1st class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM