Android實現SQLite數據庫聯系人列表
開發工具:Andorid Studio 1.3
運行環境:Android 4.4 KitKat
工程內容
實現一個通訊錄查看程序:
- 要求使用SQLite數據庫保存通訊錄,使得每次運行程序均能顯示當前聯系人的列表
- 主界面包含一個添加聯系人按鈕和一個聯系人列表,每一項顯示聯系人學號,姓名,手機號碼。
- 點擊添加聯系人按鈕能添加新的聯系人。
- 在次界面輸入聯系人信息之后點擊確定按鈕后會返回主界面。(前提輸入正確)
- 長按某個聯系人,彈出對話框,詢問是否刪除該聯系人。
- 單擊某個聯系人,彈出修改聯想人的界面。
代碼實現
為聯系人添加一個類Contact,封裝學號姓名手機號碼三個字段,並重構三個構造函數,給每個字段設置公有的get、set函數,這是類最標准的做法。
public class Contact {
private String no;
private String name;
private String phoneNumber;
public Contact() {}
public Contact(String _name, String _phoneNumber) {
this.name = _name;
this.phoneNumber = _phoneNumber;
}
public Contact(String _no, String _name, String _phoneNumber) {
this.no = _no;
this.name = _name;
this.phoneNumber = _phoneNumber;
}
public String getNo() { return no; }
public void setNo(String _no) { this.no = _no; }
public String getName() { return name; }
public void setName(String _name) { this.name = _name; }
public String getPhoneNumber() { return phoneNumber; }
public void setPhoneNumber(String _phoneNumber) { this.phoneNumber = _phoneNumber; }
}
為接下來要用到的數據庫方法新建一個類MyDatabaseHelper繼承自SQLiteOpenHelper,設置好數據庫名稱和表格名稱以及比較重要的版本號,封裝好以便后面使用。
public class MyDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "Contacts.db";
private static final String TABLE_NAME = "Contacts";
private static final int DB_VERSION = 1;
public MyDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
}
一開始是創建數據庫,這里使用自增的id字段為關鍵字,其余學號姓名手機為基本字段,創建
一個表格存儲,當這個MyDatabaseHelper被實例化的時候即創建表格,因此在onCreate()中做
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_TABLE = "create table " + TABLE_NAME
+ " (_id integer primary key autoincrement, "
+ "_no text not null, "
+ "_name text not null, "
+ "_pnumber text);";
db.execSQL(CREATE_TABLE);
}
為了能創建實例需要重載onUpgrade()函數,這里簡單地重載,但是調用會出事,整張表格內容會丟失,但在這次程序里面不會被調用,先暫且寫着
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
String DROP_TABLE = "DROP TABLE IF EXITS " + TABLE_NAME;
db.execSQL(DROP_TABLE);
onCreate(db);
}
在數據庫中插入一個聯系人,傳入一個聯系人對象即可,插入一個數據庫項
public long insert(Contact entity) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put("_no", entity.getNo());
values.put("_name", entity.getName());
values.put("_pnumber", entity.getPhoneNumber());
long id = db.insert(TABLE_NAME, null, values);
db.close();
return id;
}
在數據庫中更新聯系人,根據傳入的聯系人學號查找數據庫,將新的數據覆蓋原來數據庫中的數據即可更新
public int update(Contact entity) {
SQLiteDatabase db = getWritableDatabase();
String whereClause = "_no = ?";
String[] whereArgs = { entity.getNo() };
ContentValues values = new ContentValues();
values.put("_no", entity.getNo());
values.put("_name", entity.getName());
values.put("_pnumber", entity.getPhoneNumber());
int rows = db.update(TABLE_NAME, values, whereClause, whereArgs);
db.close();
return rows;
}
在數據庫中刪除聯系人,根據傳入的聯系人的學號查找數據庫,找到后刪除即可
public int delete(Contact entity) {
SQLiteDatabase db = getWritableDatabase();
String whereClause = "_no = ?";
String[] whereArgs = { entity.getNo() };
int rows = db.delete(TABLE_NAME, whereClause, whereArgs);
db.close();
return rows;
}
在數據庫中查詢數據庫表頭,使用query方法參數全部為空即可匹配數據庫表的第一項,返回內容是指向第一項的指針類,可以向后遍歷表格中的項
public Cursor query() {
SQLiteDatabase db = getReadableDatabase();
return db.query(TABLE_NAME, null, null, null, null, null, null);
}
為ListView建立一個MySimpleAdapter類繼承自SimpleAdapter,可以方便地綁定到ListView中
public class MySimpleAdapter extends SimpleAdapter {
private ArrayList<Map<String, String>> mData;
public MySimpleAdapter(Context context, List<? extends Map<String, ?>> data,
int resource, String[] from, int[] to) {
super(context, data, resource, from, to);
this.mData = (ArrayList<Map<String, String>>)data;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int mPosition = position;
return super.getView(position, convertView, parent);
}
}
准備工作已經做好了,剩下的就是程序的邏輯編寫。
進入主界面需要更新ListView的內容,使用剛才寫好的query方法訪問數據庫中全部的內容,加入到一個List中,並通過該List和之前寫好的ListView Item Layout創建一個MySimpleAdapter綁定到ListView中,完成更新。由於這步工作在后續的添加聯系人、修改聯系人和刪除聯系人中都使用到,因此封裝成一個函數以便調用。
private void setData(List<Map<String, String>> mDataList) {
Map<String, String> mData;
Cursor c = myDatabaseHelper.query();
while (c.moveToNext()) {
mData = new HashMap<String, String>();
mData.put("no", c.getString(c.getColumnIndex("_no")));
mData.put("name", c.getString(c.getColumnIndex("_name")));
mData.put("pnumber", c.getString(c.getColumnIndex("_pnumber")));
mDataList.add(mData);
}
}
private void updateListView() {
dataList.clear();
setData(dataList);
MySimpleAdapter mySimpleAdapter = new MySimpleAdapter(this, dataList, R.layout.contact_item,
new String[] { "no", "name", "pnumber" },
new int[] { R.id.contact_no, R.id.contact_name, R.id.contact_phonenumber });
ListView lv = (ListView)this.findViewById(R.id.lv_contact);
lv.setAdapter(mySimpleAdapter);
}
當用戶點擊添加按鈕的時候,跳轉到次界面,並傳遞消息給次界面是通過Add按鈕跳轉到這里來的,使用startActivityForResult方法,並設定Add按鈕的requestCode為1
Button btnAdd = (Button)this.findViewById(R.id.btn_add);
btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
Bundle bundle = new Bundle();
bundle.putBoolean("AddorNot", true);
intent.putExtras(bundle);
int requestCode = 1;
startActivityForResult(intent, requestCode);
}
});
次界面中根據主界面傳遞進來的消息,更新界面,顯示是否是添加聯系人或者修改聯系人,如果是添加聯系人,界面全部字段為空,如果是修改聯系人,填入原本的聯系人信息到界面字段中
Bundle bundle = getIntent().getExtras();
final boolean addOrNot = bundle.getBoolean("AddorNot");
if (addOrNot) {
tvTitle.setText(getResources().getString(R.string.titleAdd));
edtNo.setText("");
edtName.setText("");
edtPNumber.setText("");
} else {
tvTitle.setText(getResources().getString(R.string.titleModify));
edtNo.setText(bundle.getString("oldNo"));
edtName.setText(bundle.getString("oldName"));
edtPNumber.setText(bundle.getString("oldPNumber"));
}
當用戶在次界面點擊按鈕的時候,用正則表達式判斷輸入是否符合學號和手機號碼的規則,以及姓名不能為空,然后根據是添加聯系人或者修改聯系人設定返回信息,並傳遞聯系人消息回主界面
Button btnConfirm = (Button)this.findViewById(R.id.btn_confirm);
btnConfirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String newNo = edtNo.getText().toString();
String newName = edtName.getText().toString();
String newPNumber = edtPNumber.getText().toString();
if (!newNo.matches("^[1-9]\\d{7}$")
|| !newPNumber.matches("^[1-9]\\d{10}$")
|| newName.isEmpty()) {
Toast.makeText(getApplicationContext(), getResources().getString(R.string.msgWarning),
Toast.LENGTH_SHORT).show();
return;
}
Intent intent = new Intent();
intent.putExtra("_newNo", newNo);
intent.putExtra("_newName", newName);
intent.putExtra("_newPNumber", newPNumber);
int resultCode = 0;
if (addOrNot) resultCode = 1;
else resultCode = 2;
DetailActivity.this.setResult(resultCode, intent);
DetailActivity.this.finish();
}
});
主界面需要重載onActivityResult方法捕獲從次界面傳遞回來的消息,判斷是否為更新聯系人或者添加聯系人,然后均需要更新整個界面
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d("Hint", "requestCode = " + requestCode);
Log.d("Hint", "resultCode = " + resultCode);
if (resultCode == 0)
return;
String newNo = data.getStringExtra("_newNo");
String newName = data.getStringExtra("_newName");
String newPNumber = data.getStringExtra("_newPNumber");
switch (requestCode) {
case 1:
myDatabaseHelper.insert(new Contact(newNo, newName, newPNumber));
break;
case 2:
myDatabaseHelper.update(new Contact(newNo, newName, newPNumber));
break;
default:
break;
}
updateListView();
}
點擊聯系人進入修改聯系人界面(次界面),傳遞消息告訴次界面為修改聯系人,設置相應的requestCode為2
ListView lv = (ListView)this.findViewById(R.id.lv_contact);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ListView listView = (ListView) parent;
HashMap<String, String> map = (HashMap<String, String>)listView.getItemAtPosition(position);
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
Bundle bundle = new Bundle();
bundle.putBoolean("AddorNot", false);
bundle.putString("oldNo", map.get("no"));
bundle.putString("oldName", map.get("name"));
bundle.putString("oldPNumber", map.get("pnumber"));
intent.putExtras(bundle);
int requestCode = 2;
startActivityForResult(intent, requestCode);
}
});
當長按聯系人的時候,彈出彈窗詢問是否需要刪除聯系,如果用戶選擇是刪除聯系人,則使用數據庫的delete方法,並更新界面
lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
ListView listView = (ListView) parent;
final HashMap<String, String> map = (HashMap<String, String>)listView.getItemAtPosition(position);
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("確認刪除嗎?");
builder.setTitle("提示");
builder.setPositiveButton("確認", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
try {
myDatabaseHelper.delete(new Contact(map.get("no"), map.get("name"), map.get("pnumber")));
updateListView();
} catch (Exception e) {
Log.d("Hint", "Remove failed!");
}
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// nothing to do
}
});
builder.show();
return true;
}
});
基本邏輯完成,但是程序有bug,在下面會說到
效果圖
初始化界面->點擊添加->填入錯誤信息點擊確定->填入正確信息
正確信息確定后主界面增加->點擊張三進入修改->修改為正確內容->確定確定后更新
長按李四提示是否刪除->點擊確認刪除后更新界面
一些總結
當用戶在次界面點擊返回按鈕的時候,因為主界面會捕獲消息並進行相應的處理,但是返回鍵是沒有消息返回的,因此需要重載返回按鈕,否則整個程序會崩潰。通過設置resultCode為0,以區分是用返回鍵返回的
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK) {
int resultCode = 0;
DetailActivity.this.setResult(resultCode);
DetailActivity.this.finish();
}
return true;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d("Hint", "requestCode = " + requestCode);
Log.d("Hint", "resultCode = " + resultCode);
if (resultCode == 0)
return;
}
工程下載
傳送門:下載