我有一个从数据库填充的列表视图。在同一个活动中,我在列表视图上方还有一个 EditTExt 和一个 Add Category 按钮。
类别名称1 |编辑按钮 |删除按钮 类别名称2 |编辑按钮 |删除按钮 类别名称3 |编辑按钮 |删除按钮
如果我添加类别,列表视图会更新。
如果我点击删除,打开对话框(你确定吗?),当你点击是时,它会从数据库中删除它,然后更新列表视图并删除行。
如果我单击编辑按钮(位于列表视图布局的自定义适配器中),它会打开对话框并显示带有类别名称的编辑文本,您可以更改它,当您单击保存时按钮将其保存到数据库但不更新列表视图。
所以我解决了这个问题,而不是尝试重新轮询数据库以再次更新列表视图,而是获取了该行类别的位置和编辑文本并以这种方式更新。
一次只能编辑 1 个项目,我认为这没什么大不了的,直到我通过使用此解决方法遇到另一个问题。那就是:
如果您单击“类别名称 1”的“编辑”按钮,然后在对话框中将其重命名为“有意义的类别名称”。它更新数据库,它立即反映在列表视图中,但是当您在执行任何其他操作之前删除该项目时,当我将消息发送到不同的列表视图以让我知道它已被删除时,它反映了原始类别名称而不是编辑过的。
现在解决这个问题的方法是,当我想删除它时,不要依赖列表视图中的类别名称,而是在删除之前从数据库中获取类别名称,然后将其删除,然后发送带有数据库中的类别名称。
我真正想要的是以下流程,而不是使用 2 个解决方法:
使用自定义列表视图加载活动 -> 单击编辑 -> 对话框编辑从自定义适配器打开 -> 单击保存按钮 -> 数据库已更新。 -> Listview 已更新/刷新。
除了更新/刷新 Listview 之外,我已经完成了所有工作。
我已经搜索了很多东西,可以找到各种可以用来刷新列表视图的方法,但它们都不起作用,而且它们都不适用于自定义适配器对话框中的数据库更新。
我可以发布代码,但我认为这非常简单。如果没有,我很乐意发布代码。
答案 0 :(得分:0)
也许可以考虑使用 CursorAdapter,它消除了对中间数组的需求,刷新变得轻而易举。
这是一个使用 SimpleCursorAdapter 的示例,除了编辑之外,它可以执行所有操作(但是您可能需要自定义光标适配器)。但是,刷新方面没有什么不同,具体取决于适配器类型。
布局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>
数据库助手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");
}
}
_id INTEGER PRIMARY KEY
定义的(有或没有 AUTOINCREMENT(没有更有效,有很少需要,所以最好不要使用))。活动 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 按钮调用的 Activity(不只是编辑 toast)。
首先是用于 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());
}
}
结果