我創建了一個 ListView,我為其實作了一個自定義配接器。此外,我將它連接到 SQLite 資料庫,其中包含 ListView 的內容。
我有一個包含多個專案的 ListView。每個專案都由一個 TextView 和一個用作按鈕的 ImageView 組成。當用戶單擊 ImageView 時,我想從資料庫中洗掉該專案并自動更新 ListView。
不幸的是,我只知道如何從資料庫中洗掉該專案。在專案從資料庫中洗掉后,我想不出一種自動更新程式中的 ListView 的方法。
在下面的版本中,我在 MainActivity 中為 ListView 添加了一個 onItemClickListener - 但它在用戶單擊 ImageView 時不起作用(即使 ImageView 是 ListView 的一部分)。
主要活動
public class MainActivity extends AppCompatActivity {
//References to buttons and other controls on the layout
private Button btn_add;
private EditText et_todo;
private Switch sw;
private static ListView lv;
private static DataAdapter todoAdapter;
private DataBaseHelper dbHelper;
/**
* Initialization Method
*
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new DataBaseHelper(MainActivity.this);
assignVariables();
registerClick();
showAllToDos(dbHelper);
}
private void assignVariables() {
//assign values to variables
btn_add = (Button) findViewById(R.id.btn_add);
et_todo = (EditText) findViewById(R.id.et_todo);
lv = (ListView) findViewById(R.id.lv);
}
public void showAllToDos(DataBaseHelper dbHelper) {
todoAdapter = new DataAdapter(MainActivity.this, R.layout.list_item, dbHelper.getAllAsList(), dbHelper);
lv.setAdapter(todoAdapter);
}
private void registerClick() {
btn_add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String toDoTitle = et_todo.getText().toString();
if(Pattern.matches("s*", toDoTitle)) {
Toast.makeText(MainActivity.this, "Title is missing", Toast.LENGTH_SHORT).show();
} else if(dbHelper.existsInDB(new DataModel(toDoTitle))) {
Toast.makeText(MainActivity.this, "Already added as ToDo", Toast.LENGTH_SHORT).show();
} else {
DataModel dModel = new DataModel(toDoTitle);
dbHelper.addOne(dModel);
showAllToDos(dbHelper);
}
//empty input field
et_todo.setText("");
}
});
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
DataModel clickedItem = (DataModel) adapterView.getItemAtPosition(position);
dbHelper.deleteOne(clickedItem);
showAllToDos(dbHelper);
}
});
}
}
資料模型
public class DataModel {
//Attributes
private int id;
private String title;
//Constructors
public DataModel(String title) {
this.title = title;
}
public DataModel() {
}
//toString
@Override
public String toString() {
return "DataModel{"
"id=" id
", title='" title '\''
'}';
}
//Getters and Setters
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
資料配接器
public class DataAdapter extends ArrayAdapter<DataModel> {
/**
* Attributes
*/
private Context mContext;
private int mResource;
private ArrayList<DataModel> mList;
private DataBaseHelper mDbHelper;
public DataAdapter(Context context, int resource, ArrayList<DataModel> list, DataBaseHelper dbHelper) {
super(context, resource, list);
mContext = context;
mResource = resource;
mList = list;
mDbHelper = dbHelper;
}
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
//get the objects information
String title = getItem(position).getTitle();
//create object with the information
DataModel model = new DataModel(title);
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mResource, parent, false);
//get TextViews
TextView tvTitle = (TextView) convertView.findViewById(R.id.task);
//set information to TextViews
tvTitle.setText(title);
//delete function
ImageView delView = (ImageView) convertView.findViewById(R.id.delView);
delView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mDbHelper.deleteOne(model);
}
});
return convertView;
}
}
資料庫助手
public class DataBaseHelper extends SQLiteOpenHelper {
public static final String TODO_TABLE = "TODO_TABLE";
public static final String COLUMN_ID = "ID";
public static final String COLUMN_TODO_TITLE = "TODO_TITLE";
private Context mContext;
public DataBaseHelper(@Nullable Context context) {
super(context, "todo.db", null, 1);
mContext = context;
}
/**
* Is called when the app requests or inputs new data.
*
* @param db
*/
@Override
public void onCreate(SQLiteDatabase db) {
String createTableStatement = "CREATE TABLE " TODO_TABLE
" (" COLUMN_ID " INTEGER PRIMARY KEY AUTOINCREMENT,"
COLUMN_TODO_TITLE " TEXT)";
db.execSQL(createTableStatement);
//create new Table
}
/**
* Called whenever the database version number changes.
* Prevents the previous apps from crashing.
*
* @param sqLiteDatabase
* @param i
* @param i1
*/
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
/**
* method to add new database entry
*
* @param dModel
* @return
*/
public boolean addOne(DataModel dModel) {
SQLiteDatabase db = this.getWritableDatabase(); //for insert actions
ContentValues cv = new ContentValues(); //Content values stores data in pairs
cv.put(COLUMN_TODO_TITLE, dModel.getTitle());
long insert = db.insert(TODO_TABLE, null, cv);
//clean up, close connection to database and cursor
db.close();
if(insert == -1) { //if insert is negative number than insert went wrong
return false;
} else { //if insert is positive number than insert succeeded
return true;
}
}
public boolean deleteOne(DataModel dModel) {
//if DataModel is found in the database, delete it and return true
//if it is not found, return false
SQLiteDatabase db = this.getWritableDatabase();
String queryString = "DELETE FROM " TODO_TABLE
" WHERE " COLUMN_TODO_TITLE " = " "\"" dModel.getTitle() "\"";;
Cursor cursor = db.rawQuery(queryString, null);
if(cursor.moveToFirst()) {
return true;
} else {
return false;
}
}
public ArrayList<DataModel> getAllAsList() {
//create empty list
ArrayList<DataModel> returnList = new ArrayList<>();
//get data from the database
String queryString = "SELECT * FROM " TODO_TABLE;
SQLiteDatabase db = this.getReadableDatabase(); //get data from database
Cursor cursor = db.rawQuery(queryString, null);
if(cursor.moveToFirst()) { //returns a true if there were items selected
//loop through results, create new todo objects, put them into return list
do {
String todoTitle = cursor.getString(1);
DataModel newTodo = new DataModel(todoTitle);
returnList.add(newTodo);
} while(cursor.moveToNext());
} else { //returns a false if no items were selected
//failure, to not add anything to the list
}
//clean up, close connection to database and cursor
cursor.close();
db.close();
return returnList;
}
public boolean existsInDB(DataModel dModel) {
SQLiteDatabase db = this.getWritableDatabase(); //for insert actions
String queryString = "SELECT * FROM " TODO_TABLE
" WHERE " COLUMN_TODO_TITLE " = " "\"" dModel.getTitle() "\"";
Cursor cursor = db.rawQuery(queryString, null);
if(cursor.moveToFirst()) {
return true;
} else {
return false;
}
}
}
我感謝任何幫助或建議。如果您需要進一步解釋,請告訴我。
妮可
uj5u.com熱心網友回復:
在下面的版本中,我在 MainActivity 中為 ListView 添加了一個 onItemClickListener - 但它在用戶單擊 ImageView 時不起作用(即使 ImageView 是 ListView 的一部分)。
根據您的代碼考慮以下內容:-
作業示例
以下代碼基于您的代碼,但進行了各種更改,這些更改會在影像(單擊紫色框)時洗掉并重繪 串列。
list_item.xml布局(更改為將專案突出顯示為無影像):-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/teal_200">
<TextView
android:id="@ id/task"
android:layout_width="400dp"
android:layout_height="match_parent"
>
</TextView>
<ImageView
android:id="@ id/delView"
android:layout_width="100dp"
android:layout_height="20dp"
android:layout_gravity="center"
android:background="@color/purple_200"
>
</ImageView>
</LinearLayout>
DataModel類保持不變。
DatabaseHelper類已更改為 a) 不關閉資料庫(這是低效的,因為它將應用 WAL 更改,然后必須隨后打開相對資源消耗較大的資料庫)和 b) 完成后關閉所有游標和c) 利用方便的方法:-
public class DataBaseHelper extends SQLiteOpenHelper {
public static final String TODO_TABLE = "TODO_TABLE";
public static final String COLUMN_ID = "ID";
public static final String COLUMN_TODO_TITLE = "TODO_TITLE";
private Context mContext;
public DataBaseHelper(@Nullable Context context) {
super(context, "todo.db", null, 1);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
String createTableStatement = "CREATE TABLE " TODO_TABLE
" (" COLUMN_ID " INTEGER PRIMARY KEY AUTOINCREMENT,"
COLUMN_TODO_TITLE " TEXT)";
db.execSQL(createTableStatement);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
public boolean addOne(DataModel dModel) {
SQLiteDatabase db = this.getWritableDatabase(); //for insert actions
ContentValues cv = new ContentValues(); //Content values stores data in pairs
cv.put(COLUMN_TODO_TITLE, dModel.getTitle());
return db.insert(TODO_TABLE, null, cv) > -1;
}
public boolean deleteOne(DataModel dModel) {
SQLiteDatabase db = this.getWritableDatabase();
return db.delete(TODO_TABLE,COLUMN_TODO_TITLE "=?",new String[]{dModel.getTitle()}) > 0;
}
@SuppressLint("Range")
public ArrayList<DataModel> getAllAsList() {
//create empty list
ArrayList<DataModel> returnList = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TODO_TABLE,null,null,null,null,null,null);
while (cursor.moveToNext()) {
returnList.add(new DataModel(cursor.getString(cursor.getColumnIndex(COLUMN_TODO_TITLE))));
}
cursor.close();
return returnList;
}
public boolean existsInDB(DataModel dModel) {
boolean rv = false;
SQLiteDatabase db = this.getWritableDatabase(); //for insert actions
Cursor cursor = db.query(TODO_TABLE,null,COLUMN_TODO_TITLE "=?",new String[]{dModel.getTitle()},null,null,null);
if(cursor.moveToFirst()) {
rv = true;
}
cursor.close();
return rv;
}
}
資料配接器
public class DataAdapter extends ArrayAdapter<DataModel> {
/**
* Attributes
*/
private Context mContext;
private int mResource;
private ArrayList<DataModel> mList;
private DataBaseHelper mDbHelper;
public DataAdapter(Context context, int resource, ArrayList<DataModel> list, DataBaseHelper dbHelper) {
super(context, resource, list);
mContext = context;
mResource = resource;
mList = list;
mDbHelper = dbHelper;
}
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
//get the objects information
String title = getItem(position).getTitle();
//create object with the information
DataModel model = new DataModel(title);
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mResource, parent, false);
//get TextViews
TextView tvTitle = (TextView) convertView.findViewById(R.id.task);
//set information to TextViews
tvTitle.setText(title);
//delete function
ImageView delView = (ImageView) convertView.findViewById(R.id.delView);
delView.setTag(position); //<<<<< ADDDED Sets the tag with the position in the list
delView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Integer position = new Integer(view.getTag().toString()); // gets the position from the tag
DataModel model = mList.get(position); // gets the respective DataModel from the ArrayList
Toast.makeText(view.getContext(),"You clicked the Image for Title = " model.getTitle() " position " view.getTag(),Toast.LENGTH_SHORT).show();
Log.d("CLICKACTION","Image clicked for title = " model.getTitle() " position " view.getTag());
/* probably faster but the potential for issues if for some reason deletes other than expected
if (mDbHelper.deleteOne(model)) {
mList.remove(model);
notifyDataSetChanged();
}
*/
/* Alternative approach - more intensive but the resultant list IS accurate */
mDbHelper.deleteOne(model);
ArrayList<DataModel> newlist = mDbHelper.getAllAsList();
mList.clear();
for (DataModel dm: newlist) {
mList.add(dm);
notifyDataSetChanged();
}
}
});
return convertView;
}
}
- 注意一個重要的方面是利用標簽將點擊的視圖系結到 Todo/DataModel。
- 注意另一個重要因素是對 DataAdapter 的 ArrayList 實體的操作以及
notifyDatasetChanged告訴配接器重建的后續操作。
和MainActivity:-
public class MainActivity extends AppCompatActivity {
//References to buttons and other controls on the layout
private Button btn_add;
private EditText et_todo;
private Switch sw;
private static ListView lv;
private static DataAdapter todoAdapter;
private DataBaseHelper dbHelper;
/**
* Initialization Method
*
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new DataBaseHelper(MainActivity.this);
assignVariables();
registerClick();
showAllToDos(dbHelper); // creates a new instance of the adapter each time it is called
}
private void assignVariables() {
//assign values to variables
btn_add = (Button) findViewById(R.id.btn_add);
et_todo = (EditText) findViewById(R.id.et_todo);
lv = (ListView) findViewById(R.id.lv);
}
public void showAllToDos(DataBaseHelper dbHelper) {
todoAdapter = new DataAdapter(MainActivity.this, R.layout.list_item, dbHelper.getAllAsList(), dbHelper);
lv.setAdapter(todoAdapter);
}
private void registerClick() {
btn_add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String toDoTitle = et_todo.getText().toString();
if(Pattern.matches("s*", toDoTitle)) {
Toast.makeText(MainActivity.this, "Title is missing", Toast.LENGTH_SHORT).show();
} else if(dbHelper.existsInDB(new DataModel(toDoTitle))) {
Toast.makeText(MainActivity.this, "Already added as ToDo", Toast.LENGTH_SHORT).show();
} else {
DataModel dModel = new DataModel(toDoTitle);
dbHelper.addOne(dModel);
showAllToDos(dbHelper);
}
//empty input field
et_todo.setText("");
}
});
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
Toast.makeText(view.getContext(),"Item was clicked for Title = " ((DataModel) adapterView.getItemAtPosition(position)).getTitle(),Toast.LENGTH_SHORT).show();
Log.d("CLICKACTION","Item was clicked for Title" ((DataModel) adapterView.getItemAtPosition(position)).getTitle());
//DataModel clickedItem = (DataModel) adapterView.getItemAtPosition(position);
//dbHelper.deleteOne(clickedItem);
//showAllToDos(dbHelper);
}
});
}
}
*結果
從新安裝(空資料庫)開始,采取了以下措施:-
添加 Test001 - Test006 所以: -
單擊專案 Test003(不是紫色框(影像))
- Toast 按預期顯示。
- 日志包括
D/CLICKACTION: Item was clicked for TitleTest003
單擊 Test003 的洗掉影像(紫色框)
- Toast 按預期顯示 Test003 位置 2
- 日志包括
D/CLICKACTION: Image clicked for title = Test003 position 2
- ie Test003 從顯示中移除
- 通過 App Inspection 的資料庫顯示:-
- 即資料庫中沒有Test003行
uj5u.com熱心網友回復:
直接使用 SQLite 可能具有挑戰性,而且 ListView 已過時,不建議再使用。最佳實踐是使用 RecycleView
這是一個很好的教程如何使用它:
Room - 來自 Google 的 SQLite 包裝庫
LiveData - 用于訂閱實時更新
RecyclerView - 用于構建高效串列的 UI 小部件
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/490803.html
標籤:爪哇 安卓 sqlite 安卓-sqlite 定制适配器
上一篇:SQLmax是不確定的?
下一篇:多個子查詢和視窗操作SQLite

