繁体   English   中英

更新 Sqlite 数据库后,从自定义适配器对话框正按钮更新/刷新列表视图

[英]Update / Refresh Listview From Custom Adapter Dialog Possitive Button After Updating Sqlite Database

我有一个从数据库填充的列表视图。 在同一个活动中,我在列表视图上方还有一个 EditTExt 和一个添加类别按钮。

编辑文本 | 添加类别

类别名称1 | 编辑按钮 | 删除按钮类别名称2 | 编辑按钮 | 删除按钮类别名称3 | 编辑按钮 | 删除按钮

  1. 如果我添加类别,列表视图会更新。

  2. 如果我单击删除,打开对话框(您确定吗?),当您单击是时,它会从数据库中删除它,然后使用已删除的行更新列表视图。

  3. 如果我单击编辑按钮(位于列表视图布局的自定义适配器中),它会打开对话框并显示带有类别名称的编辑文本,您可以更改它,当您单击保存按钮时,它会将其保存到数据库,但更新列表视图。

所以我解决了这个问题,而不是尝试重新轮询数据库以再次更新列表视图,我抓住了 position 和该行类别的编辑文本并以这种方式更新。

一次只能编辑 1 个项目,我认为这没什么大不了的,直到我通过使用此解决方法遇到另一个问题。 那就是:

如果单击类别名称 1 的编辑按钮并在对话框中将其重命名为有意义的类别名称。 它会更新数据库,它会立即反映在列表视图中,但是当您在执行任何其他操作之前删除该项目时,当我将消息发送到不同的列表视图让我知道它已被删除时,它反映的是原始类别名称而不是编辑过的。

现在解决这个问题的方法是,当我想删除它时,不要依赖列表视图中的类别名称,而是在删除之前从数据库中获取类别名称,然后删除它,然后发送带有类别名称的消息数据库。

我真正想要的是以下流程,而不是使用这两种解决方法:

使用自定义列表视图加载活动->单击编辑->从自定义适配器打开对话框编辑->单击保存按钮->更新数据库。 -> Listview 已更新/刷新。

除了更新/刷新 Listview 之外,我已经完成了所有工作。

我搜索了高低,可以找到各种可以用来刷新列表视图的方法,但是它们都不起作用,而且它们都不能用于从自定义适配器的对话框中更新数据库。

我可以发布代码,但我认为这非常简单。 如果没有,我很乐意发布代码。

也许考虑使用 CursorAdapter 消除对中间数组的需要并且刷新是轻而易举的。

这是一个使用 SimpleCursorAdapter 的示例,除了编辑之外,它只做所有的事情(但是您可能需要一个自定义 Cursor 适配器)。 但是,刷新方面与特定适配器类型没有什么不同。

布局activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        />

    <EditText
        android:id="@+id/categoryname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        >
    </EditText>
    <Button
        android:id="@+id/addcategorybutton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ADD CATEGORY"
        >
    </Button>

    <ListView
        android:id="@+id/categorylist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
    </ListView>
</LinearLayout>
  • 即EditText、添加按钮和ListView

数据库助手DBHelper

class DBHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "category.db";
    public static final int DBVERSION = 1;

    public static final String TB_CATEGORY = "category";
    public static final String COl_ID_CATEGORY = BaseColumns._ID;
    public static final String COl_CATEGORYNAME_CATEGORY = "category_name";

    private SQLiteDatabase db;
    private static volatile DBHelper instance;

    private DBHelper(@Nullable Context context) {
        super(context, DBNAME, null, DBVERSION);
        db = this.getWritableDatabase();
    }

    public static DBHelper getInstance(Context context) {
        if (instance == null) {
            instance = new DBHelper(context);
        }
        return instance;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE IF NOT EXISTS " + TB_CATEGORY + "(" +
                COl_ID_CATEGORY + " INTEGER PRIMARY KEY" +
                "," + COl_CATEGORYNAME_CATEGORY + " TEXT UNIQUE " +
                ")");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int i, int i1) {

    }

    public long insertCategory(String categoryName) {
        ContentValues cv = new ContentValues();
        cv.put(COl_CATEGORYNAME_CATEGORY,categoryName);
        return db.insert(TB_CATEGORY,null,cv);
    }

    public int deleteCategory(long id) {
        return db.delete(TB_CATEGORY,COl_ID_CATEGORY + "=?", new String[]{String.valueOf(id)});
    }

    public int deleteCategory(String categoryName) {
        return db.delete(TB_CATEGORY,COl_CATEGORYNAME_CATEGORY + "=?",new String[]{categoryName});
    }

    public int updateCategory(Long id, String categoryName) {
        ContentValues cv = new ContentValues();
        cv.put(COl_CATEGORYNAME_CATEGORY,categoryName);
        return db.update(TB_CATEGORY,cv,COl_ID_CATEGORY+"=?", new String[]{String.valueOf(id)});
    }

    public int updateCategory(String oldCatgeoryName, String newCategoryName) {
        ContentValues cv = new ContentValues();
        cv.put(COl_CATEGORYNAME_CATEGORY,newCategoryName);
        return db.update(TB_CATEGORY,cv,COl_CATEGORYNAME_CATEGORY + "=?",new String[]{oldCatgeoryName});
    }

    public Cursor getCategories() {
        return db.query(TB_CATEGORY,null,null,null,null,null,COl_CATEGORYNAME_CATEGORY + " ASC");
    }
}
  • 注意Cursor 适配器期望(必须具有)名为_id的列(因此 BaseColumns._ID),并且该列应该是唯一的 integer 标识行。 通常使用_id INTEGER PRIMARY KEY定义 rowid 列 aka 列的别名(带或不带 AUTOINCREMENT(不带更有效,很少需要带,因此最好不要使用))。
  • 如您所见,简单的两列表 _id 和 categoryname。 添加、更新、插入、删除和提取所有行(作为光标)的方法已添加。

活动MainActivity :-

public class MainActivity extends AppCompatActivity {

    EditText categoryName;
    Button addCategory;
    ListView categoryList;
    SimpleCursorAdapter sca;
    DBHelper db;
    Cursor csr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        categoryName = this.findViewById(R.id.categoryname);
        addCategory = this.findViewById(R.id.addcategorybutton);
        categoryList = this.findViewById(R.id.categorylist);
        db = DBHelper.getInstance(this);
        setupAddCategoryButton();
        setOrRefreshCategoryListView();
    }


    public void setOrRefreshCategoryListView() {
        csr = db.getCategories();
        if (sca == null) {
            sca = new SimpleCursorAdapter(
                    this,
                    android.R.layout.simple_list_item_1,
                    csr, //<<<<<<<< The Cursor
                    new String[]{DBHelper.COl_CATEGORYNAME_CATEGORY}, //<<<<<<<< The list of columns to be displayed
                    new int[]{android.R.id.text1}, //<<<<<<<< The corresponding view id's in the layout that is to display the data from the column
                    0
            );
            categoryList.setAdapter(sca);
            categoryList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
                    DBHelper dbx = DBHelper.getInstance(view.getContext());
                    if (dbx.deleteCategory(l) > 0) {
                        setOrRefreshCategoryListView();
                    }
                    return true;
                }
            });
        } else {
            sca.swapCursor(csr);
        }
    }

    public void setupAddCategoryButton() {
        addCategory.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (categoryName.getText().toString().length() > 0) {
                    if (db.insertCategory(categoryName.getText().toString()) > 0) {
                        setOrRefreshCategoryListView();
                    }
                    categoryName.setText("");
                }
            }
        });
    }
}
  • 请参阅setOrRefreshCategoryListView ,所有需要刷新(并最初设置 ListView)都在这里完成。 你只需要调用该方法。

当上面运行时。 可以通过输入文本然后单击添加类别按钮来添加类别。 可以通过长按类别来删除类别。

结果

在添加几个类别 (1-3) 之后和添加第 4 个类别之前:-

在此处输入图像描述

点击添加:-

在此处输入图像描述

长按类别 2:-

在此处输入图像描述

补充评论

我只是想在从警报对话框更新后,有一种方法可以从自定义适配器本身内刷新列表视图。

也许考虑以下显示从适配器内部刷新(即热 DLT 按钮和项目被删除和刷新)

以及通过 EDIT 按钮调用的活动(不只编辑 toasts)。

首先是用于 CustomAdapter 的布局

  • CursorAdapter 的子类,我仍然会推荐它而不是 ArrayAdapter(即 CursorAdapter 的存在是有原因的)。

     <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/categoryname" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="6"> </TextView> <Button android:id="@+id/categoryedit" android:layout_width="0dp" android:layout_weight="2" android:layout_height="match_parent" android:text="EDIT" android:onClick="onClickEditCategoryButton" android:layout_marginRight="2dp" > </Button> <Button android:id="@+id/categorydelete" android:layout_width="0dp" android:layout_weight="2" android:layout_height="match_parent" android:text="DLT" > </Button> </LinearLayout>
  • 注意EDIT 按钮指定了 onCLick,因此 onClicklistener 代码代表您进行编码。

DBHelper与上面没有变化。

MainActivity现在是:-

public class MainActivity extends AppCompatActivity {

    EditText categoryName;
    Button addCategory;
    ListView categoryList;
    CustomAdapter ca;
    DBHelper db;
    Cursor csr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        categoryName = this.findViewById(R.id.categoryname);
        addCategory = this.findViewById(R.id.addcategorybutton);
        categoryList = this.findViewById(R.id.categorylist);
        db = DBHelper.getInstance(this);
        setupAddCategoryButton();
        setOrRefreshCustomCategoryListView();
    }

    public void setOrRefreshCustomCategoryListView() {
        csr = db.getCategories();
        if (ca == null) {
            ca = new CustomAdapter(this,csr);
            categoryList.setAdapter(ca);
        } else {
            ca.swapCursor(csr);
        }
    }

    public void onClickEditCategoryButton(View v) {
        switch (v.getId()) {
            case R.id.categoryedit: {
                Toast.makeText(this, "You Clicked Edit for Category with ID of " + v.getTag(), Toast.LENGTH_SHORT).show();
                setOrRefreshCustomCategoryListView();
            }
            break;
        }
    }

    public void setupAddCategoryButton() {
        addCategory.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (categoryName.getText().toString().length() > 0) {
                    if (db.insertCategory(categoryName.getText().toString()) > 0) {
                        setOrRefreshCustomCategoryListView();
                    }
                    categoryName.setText("");
                }
            }
        });
    }
}

最后一个CustomAdapter :-

class CustomAdapter extends CursorAdapter {

    CustomAdapter(Context context, Cursor csr) {
        super(context,csr, android.widget.CursorAdapter.IGNORE_ITEM_VIEW_TYPE);
    }

    @Override
    public View newView(Context context, Cursor csr, ViewGroup parent) {
        return LayoutInflater.from(context).inflate(R.layout.categorylist,parent,false);
    }

    @Override
    public void bindView(View view, Context context, Cursor csr) {
        TextView categoryName = view.findViewById(R.id.categoryname);
        categoryName.setText(csr.getString(csr.getColumnIndex(DBHelper.COl_CATEGORYNAME_CATEGORY)));
        // Set Button tags with id of current row
        // NOTE button onClick listener set in layout
        String id = csr.getString(csr.getColumnIndex(DBHelper.COl_ID_CATEGORY));
        view.findViewById(R.id.categoryedit).setTag(id);
        view.findViewById(R.id.categorydelete).setTag(id);
        view.findViewById(R.id.categorydelete).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context,"You Clicked Delete",Toast.LENGTH_SHORT).show();
                DBHelper.getInstance(context).deleteCategory(Long.parseLong(view.getTag().toString()));
                refreshListView(context);
            }
        });
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return super.getView(position, convertView, parent);
    }

    public void refreshListView(Context context) {
        this.swapCursor(DBHelper.getInstance(context).getCategories());
    }
}

结果

现在看起来像这样(单击编辑 toasts(通过活动),单击 DLT 删除(通过适配器)) 在此处输入图像描述

暂无
暂无

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

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