可以使用按钮删除从项目添加的数据库条目吗?

时间:2017-08-16 20:05:01

标签: java android android-sqlite

我正在尝试使用“Android编程:大书呆子牧场指南”教授自己的Android开发,其中一个练习(如果您熟悉本书,请参阅第14章)涉及创建一个带有添加新项目的工具栏单击项目时数据库的条目。挑战问题是删除条目,但我想删除条目中的WITHIN条目。对不起,如果我没有做好解释这个。

基本上第一次打开应用程序时,大多数都是空的显示屏,工具栏右上角有两个项目。 Here is a screenshot if it helps。这两个项目添加或计算条目数,然后显示在列表中。在上图中,有一个条目。单击+符号时,会添加一个新条目,它会将您带到layout以获取允许您添加所有详细信息的条目。我想添加一个删除按钮,允许您在查看详细信息时删除条目。

这是我尝试过的代码,但没有用到: 在CrimeLab.java中

public void addCrime(Crime c){
    ContentValues values = getContentValues(c);

    mDatabase.insert(CrimeTable.NAME, null, values);
}

public void deleteCrime(Crime crimeId){

    String uuidString = crimeId.toString();
    mDatabase.delete(CrimeTable.NAME, null, new String[] 
{uuidString});
}

我基本上试图撤消创建数据库条目时所做的操作。 在CrimeListFragment.java中:

@Override
public boolean onOptionsItemSelected(MenuItem item){
    switch (item.getItemId()){
        case R.id.menu_item_new_crime:
            Crime crime = new Crime();
            CrimeLab.get(getActivity()).addCrime(crime);
            Intent intent = 
CrimePagerActivity.newIntent(getActivity(), crime.getId());
            startActivity(intent);
            return true;
        case R.id.menu_item_show_subtitle:
            mSubtitleVisible = !mSubtitleVisible;
            getActivity().invalidateOptionsMenu();
            updateSubtitle();
            return true;
        case R.id.delete_button:
            Crime mCrime = new Crime();
            CrimeLab.get(getActivity()).deleteCrime(mCrime);
        default:
            return super.onOptionsItemSelected(item);
    }
}

我想我需要创建一个onClick操作,但是如果我试图从条目中的项目创建的数据库中删除条目,那么这会是什么呢?

我想添加的其他内容是通过滑动显示删除按钮来删除原始页面中的条目,就像在信使应用程序中一样。

很抱歉,如果我没有正确提出我的问题。这对我来说是一个全新的世界,随着这本书的出现很有帮助,但我发现很容易让你觉得你理解了一些东西然后完全迷失了。 此外,我检查了stackoverflow和其他各种论坛,但没有找到这个问题的确切答案。

根据请求,这是Crime.java的代码:

public class Crime {
    private String mTitle;
    private Date mDate;
    private boolean mSolved;
    private String mSuspect;

    public Date getDate() {
        return mDate;
    }

    private UUID mId;

    public void setDate(Date date) {
        mDate = date;
    }

    public void setSolved(boolean solved) {
        mSolved = solved;
    }

    public String getSuspect(){
        return mSuspect;
    }

    public  void setSuspect (String suspect){
        mSuspect = suspect;
    }

    public String getPhotoFilename(){
        return "IMG_" + getId().toString() + ".jpg";
    }

    public boolean isSolved() {

        return mSolved;
    }



    public Crime(){
        //generate unique identifier
        this(UUID.randomUUID());
    }

    public Crime(UUID id){
        mId = id;
        mDate = new Date();
    }

    public UUID getId() {
        return mId;
    }

    public String getTitle() {
        return mTitle;
    }

    public void setTitle(String title) {
        mTitle = title;
    }
}

这是控制我的数据库条目的.java类:

public class CrimeBaseHelper extends SQLiteOpenHelper{
    private static final int VERSION = 1;
    private static final String DATABASE_NAME = "crimeBase.db";

    public CrimeBaseHelper(Context context){
        super(context, DATABASE_NAME, null, VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db){
        db.execSQL("create table " + CrimeTable.NAME + "(" +
                " _id integer primary key autoincrement, " +
                CrimeTable.Cols.UUID + ", " +
                CrimeTable.Cols.TITLE + ", " +
                CrimeTable.Cols.DATE + ", " +
                CrimeTable.Cols.SOLVED + ", " +
                CrimeTable.Cols.SUSPECT +
                ")"
        );

    }

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

    }
}

这就是我弄乱.onClickListener

的地方
mDeleteButton = (Button)v.findViewById(R.id.delete_button);
        mDeleteButton.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v){
                Crime mCrime = new crime();
                mCrime.getId()
                CrimeLab.get(getActivity()).deleteCrime(mCrime);
            }
                                         }
        );

2 个答案:

答案 0 :(得分:1)

我认为mDatabase.delete(CrimeTable.NAME, null, new String[] {uuidString});不正确。

第二个参数应该是选择标准或 where子句(少于WHERE关键字)
例如yourtablecolumn = yourvalue

第3个参数可以与第2个一起使用。第二个可以有一个占位符或许多占位符用于更复杂的选择标准)。所以在你的例子中,它将是: -

String whereclause = "mycolumn=?";
mDatabase.delete(CrimeTable.NAME,whereclause, new String[]{uuidString});

显然 mycolumn 会被实际的列名替换。

您可能会发现这个有用的SQLiteDatabase - delete

其他问题

另外,你有: -

        case R.id.delete_button:
            Crime mCrime = new Crime();
            CrimeLab.get(getActivity()).deleteCrime(mCrime);

犯罪对象的构造函数,从数据库获取所有数据,可能是mCrime基本上没有任何实际可用数据(无法告知所提供的信息,因此可能包含完整的Crime类代码)

此外,CrimeDelete,期望并获得一个Crime对象,你将其命名为crimeid,这很可能不是Crimetable中条目的id,而是将Crimeobject转换为字符串。

你很可能

a)需要在Crime mCrime = new Crime();

之后设置Crime对象的适当值

然后

b)在“删除犯罪”中从犯罪分子获取适当的犯罪率值。方法。我建议不要使用犯罪嫌疑人,而是使用更具描述性的内容。

假设你的Crime类有一个成员mID,它根据CrimeTable中的内容保存唯一标识符,那么就是: -

case R.id.delete_button
    Crime mCrime = new crime();
    mCrime.setID(ID_obtained_from_displayed_crime);
    CrimeLab.get(getActivity()).deleteCrime(mCrime);


public void deleteCrime(Crime crime){

    mDatabase.delete(CrimeTable.NAME, "IDCOLUMN=?", new String[] 
{crime.getID()});
}

这假设犯罪类中的方法setID()String getID(),并且IDCOLUMN是用于unqiue标识符的列(例如,存在一个),例如它将被定义为columnname INTEGER PRIMARY KEYcolumnname INTEGER PRIMARY KEY AUTOINCREMENT(ps不建议后者,因为它很可能不需要并且有开销)。

包含Crime.java和DBHelper

之后的添加

Crime mCrime = new crime();

将构造一个名为mCrime的对象,该对象具有随机生成的UUID,该UUID很可能不是存储在数据库中的UUID,更不可能是要删除的UUID。

正如您已经_id integer primary key autoincrement,(PS AUTOINCREMENT最好根据SQLite Autoincrement 删除,但不是问题)那么UUID几乎没有任何需要,因为您将依赖于什么?在数据库中, _id 列是理想的。

当你插入它时,返回插入行的 id ,这样你就可以轻松地使用: -

public long addCrime(Crime c){
    ContentValues values = getContentValues(c);
    return mDatabase.insert(CrimeTable.NAME, null, values);
}

所以你可以: -

  • 在片段/活动代码long MyCrimeID;

  • 的开头
  • 更改CrimeLab.get(getActivity()).addCrime(crime);

    • myCrimeID = CrimeLab.get(getActivity()).addCrime(crime);

请注意! id将始终为1或更大,0表示未插入(不应该发生,因为根据您的表定义,只有_id列必须是唯一的。)

我建议将crimeDelete更改为例如public int deleteCrime(long id){ String whereclause = "-id=?"; String[] whereargs = {Long.toString(id)}; return mDatabase.delete(CrimeTable.NAME, whereclause, whereargs); } 。它可能是: -

CrimeLab.get(getActivity()).deleteCrime(myCrimeID);

您会注意到它返回一个整数,这是受影响的行数。 0 =没有删除,你希望它是1.所以你现在可以检查是否有任何内容被删除。

所以你可以这样做: -

onCreate

注意!如果您确实更改了表的结构,则需要删除应用程序的数据,因为只有在数据库文件不存在时才会自动调用 public void showAll(String table) { Cursor csr = mDatabase.query(table,null,null,null,null,null,null); String rowinfo; while (csr.moveToNext()) { rowinfo = "Row " + Integer.toString(csr.getPosition()) + " has:-"; for (int i=0; i < csr.getColumnCount(); i++) { rowinfo = rowinfo + "\n\t Column Name=" + csr.getColumnName(i) + " with a value of " + csr.getString(i); } Log.d("SHOWALL",rowinfo); } }

这假设是一个非常基本的场景,您只能删除刚刚添加的内容。

根据评论,这里有一些代码可以让你看到表格中的内容: -

CrimeLab.get(getActivity()).showALL(CrimeTable.NAME);

使用

在适当的位置调用此方法
08-17 09:55:46.073 2310-2310/mjt.cardoniser D/SHOWALL: Row 0 has:-
                                                         Column Name=_id with a value of 2
                                                         Column Name=username with a value of NotMikeatAll
                                                         Column Name=userhash with a value of DZQGvy0a9l0M/kmpmDlR8Q==

                                                         Column Name=usersalt with a value of YaqqUZVgOO6OOG4cnAyQndipcEw6YWNAV5DvJKl8gRA=

                                                         Column Name=userflags with a value of 0

然后,这将在以下行中添加行: -

playlist = QMediaPlaylist()
url = QUrl.fromLocalFile("./sound2.mp3")
playlist.addMedia(QMediaContent(url))
playlist.setPlaybackMode(QMediaPlaylist.Loop)

player = QMediaPlayer()
player.setPlaylist(playlist)
player.play()

上述内容还提供了一些使用 Cursor 来提取/访问数据库中数据的方法。

答案 1 :(得分:1)

替代答案

以下是一个非常基本但有效的例子的代码。但是,通过合并 ListView 并允许通过LongClicking ListView 中的项目进行删除,它会更进一步。

但是,这并没有使用片段。

有3段代码, MainActivity MainActivity.java),SQLiteOpenHelper子类 CrimeDBHelper CrimeDBHelper.java)和MainActivity的布局,activity_main.xml: -

activity_main.xml中

这非常简单。请注意,它最后包含 ListView

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="The Crime Thing"
    android:layout_gravity="center"
    android:textStyle="bold"/>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <TextView
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:text="Crime Title"
        />
    <EditText
        android:id="@+id/crimetitle"
        android:layout_width="0dp"
        android:layout_weight="3"
        android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <TextView
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:text="Crime Date"
        />
    <EditText
        android:id="@+id/crimedate"
        android:layout_width="0dp"
        android:layout_weight="3"
        android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <TextView
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:text="Suspect"
        />
    <EditText
        android:id="@+id/crimesuspect"
        android:layout_width="0dp"
        android:layout_weight="3"
        android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <TextView
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:text="Crime Solved?"
        />
    <CheckBox
        android:id="@+id/crimesolved"
        android:layout_width="0dp"
        android:layout_weight="3"
        android:layout_height="wrap_content" />
</LinearLayout>
<Button
    android:id="@+id/addcrime"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="ADD CRIME"/>
<Button
    android:id="@+id/dltcrime"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="DLT CRIME (ID=?)"/>
<ListView
    android:id="@+id/crimelist"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
</ListView>

CrimeDBHelper.java

大多数是相似的,除了附加方法 getCrimeList() 之外,它返回一个Cursor,其中包含来自crime表的所有数据(用于填充ListView)。

public class CrimeDBHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "crimesdb";
    public static final int DBVERSION = 1;
    public static final String CRIMESTABLE = "crimes";
    public static final String CRIMEID_COL = "_id";
    public static final String CRIMETITLE_COL = "crimetitle";
    public static final String CRIMEDATE_COL = "crimedate";
    public static final String CRIMESUSPECT_COL = "crimesuspect";
    public static final String CRIMESOLVED_COL = "crimesolved";


    public static final String TABLECRTSQL =
            "CREATE TABLE " + CRIMESTABLE + "(" +
                    CRIMEID_COL + " INTEGER PRIMARY KEY," +
                    CRIMETITLE_COL + " TEXT," +
                    CRIMEDATE_COL + " TEXT, " +
                    CRIMESUSPECT_COL + " TEXT, " +
                    CRIMESOLVED_COL + " INTEGER" +
                    ");";

    public CrimeDBHelper(Context context) {
        super(context, DBNAME, null, DBVERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(TABLECRTSQL);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldversion, int newversion) {
    }

    public long addCrime(String crimetitle, String crimedate, String crimesuspect, int crimesolved) {

        SQLiteDatabase db = getWritableDatabase();

        ContentValues cv = new ContentValues();
        cv.put(CRIMETITLE_COL,crimetitle);
        cv.put(CRIMEDATE_COL,crimedate);
        cv.put(CRIMESUSPECT_COL,crimesuspect);
        cv.put(CRIMESOLVED_COL,crimesolved);
        return db.insert(CRIMESTABLE,null,cv);
    }

    public int deleteCrime(long crimeid) {
        SQLiteDatabase db = getWritableDatabase();
        String whereclause = CRIMEID_COL + "=?";
        String[] whereargs = {Long.toString(crimeid)};
        return db.delete(CRIMESTABLE,whereclause,whereargs);
    }

    public Cursor getCrimeList() {
        SQLiteDatabase db = getWritableDatabase();
        return db.query(CRIMESTABLE,null,null,null,null,null,null,null);
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {

    EditText mCrimeTitle;
    EditText mCrimeDate;
    EditText mCrimeSuspect;
    CheckBox mCrimeSolved;

    Button mAddCrime;
    Button mDltCrime;
    ListView mCrimeList;

    CrimeDBHelper dbhlpr = new CrimeDBHelper(this);
    Cursor crimelist;
    SimpleCursorAdapter sca;

    long lastcrimeid;

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

        mCrimeTitle = (EditText) findViewById(R.id.crimetitle);
        mCrimeDate = (EditText) findViewById(R.id.crimedate);
        mCrimeSuspect = (EditText) findViewById(R.id.crimesuspect);
        mCrimeSolved = (CheckBox) findViewById(R.id.crimesolved);
        mCrimeList = (ListView) findViewById(R.id.crimelist);
        mAddCrime = (Button) findViewById(R.id.addcrime);
        mDltCrime = (Button) findViewById(R.id.dltcrime);

        crimelist = dbhlpr.getCrimeList();

        // Setup Button to Add a crime
        mAddCrime.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int solved = 0;
                if (mCrimeSolved.isChecked()) {
                    solved = 1;
                }
                lastcrimeid =  dbhlpr.addCrime(
                        mCrimeTitle.getText().toString(),
                        mCrimeDate.getText().toString(),
                        mCrimeSuspect.getText().toString(),
                        solved
                );
                mDltCrime.setText("DLT CRIME (ID=" + Long.toString(lastcrimeid) + ")");
                mDltCrime.setTag(lastcrimeid);
                crimelist = dbhlpr.getCrimeList();
                sca.swapCursor(crimelist);
            }
        });

        // Setup button to delete the latest Crime added
        mDltCrime.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //dbhlpr.deleteCrime(lastcrimeid); can do it this way
                if (view.getTag() != null) {
                    dbhlpr.deleteCrime((long)view.getTag());
                    crimelist = dbhlpr.getCrimeList();
                    sca.swapCursor(crimelist);
                }
            }
        });

        sca = new SimpleCursorAdapter(this,
                android.R.layout.simple_list_item_1,
                crimelist,
                new String[]{CrimeDBHelper.CRIMETITLE_COL},
                new int[]{android.R.id.text1},
                0
        );
        mCrimeList.setAdapter(sca);

        mCrimeList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
                dbhlpr.deleteCrime(l);
                crimelist = dbhlpr.getCrimeList();
                sca.swapCursor(crimelist);
                return true;
            }
        });

    }

    protected void onDestroy() {
        super.onDestroy();
        if (crimelist != null) {
            crimelist.close();
        }

    }
}

首先要注意的是行long lastcrimeid;,这是在类级别声明的,因此在整个过程中都非常有用(你遇到的问题 long databaseID 的)。

您可能还会注意到 SimpleCursorAdapter sca; 这将用于 ListView 基本上它会将光标中的数据放入ListView )。

您应该熟悉以下大部分代码。在summray: -

  • 调用super.onCreate。
  • 活动设置为使用activity_main.xml布局。
  • 在加载布局后,将获得与视图关联的ID。
  • 获取光标获取数据库中的当前犯罪(可能没有,这不是问题)。

  • 添加了添加犯罪的按钮侦听器。请注意,这会使用已添加行的返回 _id 两次(实际上是3次,因为它会相应地更改删除按钮文本)。

    • lastcrimeid 是通过返回addCrime()方法设置的。
    • mDltCrime.setTag(lastcrimeid);将删除按钮的标记设置为添加的行的 _id

    • 另请注意,还存在另外两行,即crimelist = dbhlpr.getCrimeList();sca.swapCursor(crimelist);

      • 第一个将光标替换为现在在数据库中的内容(即包括已添加的行),第二个告诉ListView使用新光标,因此使ListView显示数据库中现在的内容(删除行时再次使用它。)
    • 然后添加删除按钮的按钮侦听器。这可以通过两种方式工作。可以使用 lastcrimeid ,或者可以使用按钮按钮来保存要删除的行的 _id 。代码将前者注释掉,因此使用后一种方法(即检索按钮标记中的值)。

      • 请注意,后一种方法的缺点是值可能为null,这会导致空指针异常,因此if (view.getTag != null)
    • 如上所述,用于刷新 ListView

    • 接下来设置SimpleCursorAdapter,它需要5个参数: -

      • 要使用的布局(android.R.layout.simple_list_item_1)是一种股票布局。
      • 要以光标形式使用的数据。注意!必须存在一个名为 _id 的列(出于这个原因,通常总是使用_id INTEGER PRIMARY KEY)注意我们得到一个Cursor {{1} 通过crimelist方法。
      • 光标中要从中检索数据的列。
      • 将放置检索到的数据的布局中的视图。
      • 我无法回想起目的的价值。但是0可以使用。不编码此第5个参数可能会导致不推荐的消息。
      • (注意我通常使用Custom CursorAdapters,因为它们更灵活,所以很少使用Simples)。
  • 然后告诉ListView按照getCrimeList使用适配器。

  • 然后将mCrimeList.setAdapter(sca);添加到ListView,这将删除长时间点击的犯罪(长l是 _id 值,因此CursorAdapter需要< strong> _id ,因此为onItemLongClickListener}。

    • 再次刷新 ListView
  • 最后,当活动仍在使用时使用游标dbhlpr.deleteCrime(l);方法用于关闭游标(游标应该在完成时始终关闭)。

这是它的外观(不漂亮但功能齐全),添加了三个犯罪(删除按钮将删除世纪之罪犯罪)。长期点击任何列出的犯罪将删除该犯罪。单击“添加”将为“Century of the Century”添加另一个条目,除非数据已更改。

enter image description here