您的位置:首页 > 移动开发

自制的通讯录APP(SQLite的应用)

2016-06-28 00:39 1006 查看
转载请附上本文链接并标明作者。

这几天做了一个通讯录APP,主要难点是自己在SQlite建表而不是读取手机联系人的信息以及对SearchView的应用,另外还添加了生日提醒功能,由于时间关系并没有太多注释,可读性一般,也相对粗糙。建议在了解SQliteOpenHelper,Cursor,SimpleCursorAdapter,ListView和adapter等知识之后阅读,会容易理解。适合练手,有什么问题请留言指正,欢迎大牛指点。

(SDK:4.3,开发工具:AS1.5)

1.建立一个ContactDBhelper继承自SQliteOpenHelper类

public class ContactDBHelper extends SQLiteOpenHelper {

private static final String DB_NAME = "CONTACT_DB";
private static final String TBL_NAME = "CONTACT_TBL";
//"_id"很重要,最好加上.name存放姓名,number存放电话,千万别和我一样存int型!还有month和day分别对应月和日,用data型,这里用int型是巨大失误导致后面判断日期是十分麻烦.
private static final String CREAT_TBL ="create table CONTACT_TBL(_id INTEGER PRIMARY KEY AUTOINCREMENT,name string(20),number int,month int,day int)";
private static SQLiteDatabase db;
public static final int VERSION = 1;

public ContactDBHelper(Context context) {
super(context,DB_NAME, null,VERSION);
}

public void onCreate(SQLiteDatabase db){
this.db = db;
db.execSQL(CREAT_TBL);
}

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

}

public void close(){
if(db != null){
db.close();
}
}
}


2.点击添加进入addActivity来添加用户,主要用到了ContentValues.put方法。

public class addActivity extends ActionBarActivity {

private EditText iname;
private EditText inumber;
private EditText imonth;
private EditText iday;
private Button ensure,cancel;

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

iname = (EditText)findViewById(R.id.input_name);
inumber = (EditText)findViewById(R.id.input_number);
imonth = (EditText)findViewById(R.id.input_month);
iday = (EditText)findViewById(R.id.input_day);
ensure =(Button)findViewById(R.id.action_ensure);
cancel = (Button)findViewById(R.id.action_cancel);

ensure.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ContactDBHelper contactDBHelper = new ContactDBHelper(getBaseContext());
SQLiteDatabase db = contactDBHelper.getWritableDatabase();

ContentValues cv = new ContentValues();
cv.put("name", iname.getText().toString());
cv.put("number", Integer.parseInt(inumber.getText().toString()));
cv.put("month", Integer.parseInt(imonth.getText().toString()));
cv.put("day", Integer.parseInt(iday.getText().toString()));
db.insert("CONTACT_TBL",null,cv);

addActivity.this.finish();
}
});

cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
addActivity.this.finish();
}
});
}
}


3.点击ListView上的用户名跳转到ModifyActivity,详情页的概念。点击修改可以修改联系人信息,并单击完成保存,原理是用update更新表。

public class ModifyActivity extends ActionBarActivity {

private EditText rname;
private EditText rnumber;
private EditText rmonth;
private EditText rday;
private Button change,stop;
private ImageButton phone,msg;
private int position;

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

rname = (EditText)findViewById(R.id.read_name);
rnumber = (EditText)findViewById(R.id.read_number);
rmonth = (EditText)findViewById(R.id.read_month);
rday = (EditText)findViewById(R.id.read_day);
ch
4000
ange =(Button)findViewById(R.id.action_change);
stop = (Button)findViewById(R.id.action_stop);
phone = (ImageButton)findViewById(R.id.phone);
msg = (ImageButton)findViewById(R.id.msg);

Bundle bundle = this.getIntent().getExtras();
position = bundle.getInt("position");

ContactDBHelper contactDBHelper = new ContactDBHelper(getBaseContext());
SQLiteDatabase dbr = contactDBHelper.getReadableDatabase();
Cursor cursor= dbr.query("CONTACT_TBL", null, null, null, null, null, null);
cursor.moveToPosition(position);
rname.setText(cursor.getString(cursor.getColumnIndex("name")));
rnumber.setText(cursor.getString(cursor.getColumnIndex("number")));
rmonth.setText(cursor.getString(cursor.getColumnIndex("month")));
rday.setText(cursor.getString(cursor.getColumnIndex("day")));
rname.setEnabled(false);
rnumber.setEnabled(false);
rmonth.setEnabled(false);
rday.setEnabled(false);

change.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ContactDBHelper contactDBHelper = new ContactDBHelper(getBaseContext());
SQLiteDatabase db = contactDBHelper.getWritableDatabase();
Cursor cursor = db.query("CONTACT_TBL", null, null, null, null, null, null);
cursor.moveToPosition(position);
int itemID = cursor.getInt(cursor.getColumnIndex("_id"));
String[] which = new String[]{itemID + ""};
ContentValues cv = new ContentValues();
cv.put("name", rname.getText().toString());
cv.put("number", Integer.parseInt(rnumber.getText().toString()));
cv.put("month", Integer.parseInt(rmonth.getText().toString()));
cv.put("day", Integer.parseInt(rday.getText().toString()));
db.update("CONTACT_TBL", cv, "_id=?", which);
ModifyActivity.this.finish();
}
});

stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ModifyActivity.this.finish();
}
});

phone.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + rnumber.getText()));
ModifyActivity.this.startActivity(intent);
}
});

msg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Uri sms = Uri.parse("smsto:"+rnumber.getText());
Intent intent = new Intent(Intent.ACTION_SENDTO, sms);
ModifyActivity.this.startActivity(intent);
}
});
}

public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_modify:
rname.setEnabled(true);
rnumber.setEnabled(true);
rmonth.setEnabled(true);
rday.setEnabled(true);
}
return super.onOptionsItemSelected(item);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_modify, menu);
return true;
}

}


4.自定义Myadapter用于SearchView。

public class Myadapter extends BaseAdapter implements Filterable {
private Context context;
private List<String> data , copyData ;

public Myadapter(Context context, List<String> data) {
super();
this.context = context;
this.data = data;
copyData = data ;
}

@Override
public int getCount() {
return data.size() ;
}

@Override
public Object getItem(int position) {
return data.get(position) ;
}

@Override
public long getItemId(int position) {
return position ;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view ;
if(null == convertView) {
view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, null) ;
}
else {
view = convertView ;
}
TextView tv = (TextView) view.findViewById(android.R.id.text1) ;
tv.setText(data.get(position)) ;
return view ;
}

private Filter myFilter ;
@Override
public Filter getFilter() {
if(null == myFilter) {
myFilter = new MyFilter() ;
}
return myFilter ;
}

class MyFilter extends Filter{
// 定义过滤规则
protected FilterResults performFiltering(CharSequence constraint) {
List<String> filterData = new ArrayList<String>() ;

if(constraint != null && constraint.toString().trim().length() > 0) {
String key = constraint.toString().trim().toLowerCase() ;
for (String item : copyData) {
if(item.toLowerCase().indexOf(key) != -1) {
filterData.add(item) ;
}
}
}
else {  //如果搜索框为空,就恢复原始数据
filterData = copyData ;
}
FilterResults results = new FilterResults() ;
results.values = filterData ;
results.count = filterData.size() ;
return results ;
}

@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {

data = (List<String>) results.values ;
if(results.count > 0) {
notifyDataSetChanged() ;
}
else {
notifyDataSetInvalidated() ;
}
}

} ;

}


5.实现搜索框的方法是:点击EditText跳转到SearchActivity,利用SearchActivity里的SearchView来实现。此时就需要实例化前面自定义的Myadapter类。

public class SearchActivity extends ActionBarActivity {

private static final String TBL_NAME = "CONTACT_TBL";

private static ContactDBHelper contactDBHelper;
private static SQLiteDatabase dbRead;
private static SQLiteDatabase dbWrite;
private static Cursor cursor;
private static ContentValues cv;

public SearchView searchView;
public ListView listView2;

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

searchView = (SearchView)findViewById(R.id.search_view);
listView2 = (ListView)findViewById(R.id.listview2);
listView2.setTextFilterEnabled(true) ;

contactDBHelper = new ContactDBHelper(this);
dbWrite = contactDBHelper.getWritableDatabase();
dbRead = contactDBHelper.getReadableDatabase();
cursor = dbRead.query(TBL_NAME, null, null, null, null, null, null);
//遍历表得到data,用于实例化Myadapter
List<String> data = new ArrayList<String>();
if(cursor!=null&&cursor.moveToFirst()){
do{
data.add(cursor.getString(cursor.getColumnIndex("name")));
}while(cursor.moveToNext());
};

Myadapter myadapter = new Myadapter(SearchActivity.this,data);
listView2.setAdapter(myadapter);

searchView.setIconifiedByDefault(false);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {

public boolean onQueryTextSubmit(String s) {
return true;
}

@Override
public boolean onQueryTextChange(String s) {
if (s != null && s.length() > 0) {
listView2.setFilterText(s);
} else {
listView2.clearTextFilter();
}
return true;
}
});

//设置listview点击事件
listView2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
cursor.moveToPosition(position);
Intent intent = new Intent(SearchActivity.this, ModifyActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("position", position);
intent.putExtras(bundle);
startActivity(intent);
}
});
//设置listview长按事件
listView2.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, final int position, long l) {
new AlertDialog.Builder(SearchActivity.this)
.setTitle("是否删除该联系人?")
.setNegativeButton("取消", null)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
cursor.moveToPosition(position);
int itemID = cursor.getInt(cursor.getColumnIndex("_id"));
String[] which = new String[]{itemID + ""};
dbWrite.delete(TBL_NAME, "_id=?", which);
refreshListView();
}
}).show();

return true;
}
});
}
public void refreshListView(){
cursor = dbRead.query(TBL_NAME, null, null, null, null, null, null);
List<String> data = new ArrayList<String>();
if(cursor!=null&&cursor.moveToFirst()){
do{
data.add(cursor.getString(cursor.getColumnIndex("name")));
}while(cursor.moveToNext());
};

Myadapter myadapter = new Myadapter(SearchActivity.this,data);
listView2.setAdapter(myadapter);

}
@Override
protected void onResume(){
super.onResume();
refreshListView();
}

}


6.最后是主活动。长按LiteView上的Item先弹出是否删除的对话框,选择是删除。删除主要靠delete()方法。

public class MainActivity extends ActionBarActivity {

public static final String TBL_NAME = "CONTACT_TBL";

public static ContactDBHelper contactDBHelper;
public static SQLiteDatabase dbRead;
public static SQLiteDatabase dbWrite;
public static Cursor cursor;
public static ContentValues cv;

public ListView listView;
public EditText editText;

public SimpleCursorAdapter listAdapter;

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

listView = (ListView) findViewById(R.id.listview);
editText = (EditText)findViewById(R.id.edittext);

editText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,SearchActivity.class);
startActivity(intent);
}
});

contactDBHelper = new ContactDBHelper(this);
dbWrite = contactDBHelper.getWritableDatabase();

//        cv = new ContentValues();
//
//        cv.put("name", "jonsnow");
//        cv.put("number", 9257);
//        cv.put("month", 3);
//        cv.put("day",10);
//        dbWrite.insert(TBL_NAME, null, cv);
//
//
//        cv.put("name", "james");
//        cv.put("number", 3154);
//        cv.put("month", 6);
//        cv.put("day",12);
//        dbWrite.insert(TBL_NAME, null, cv);
//
//
//        cv.put("name", "curry");
//        cv.put("number", 8080);
//        cv.put("month", 4);
//        cv.put("day",25);
//        dbWrite.insert(TBL_NAME, null, cv);

//dbWrite.delete(TBL_NAME,null,null);
dbRead = contactDBHelper.getReadableDatabase();
cursor = dbRead.query(TBL_NAME, null, null, null, null, null, null);

String[] from = new String[]{"name"};
int[] to = new int[]{R.id.name};
//SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags).
//五个参数的实例化SimpleCursorAdapter方法已经被废弃,然而笔者将第六个参数flag设为0,却始终无法编译成功,查了很多资料仍无法解决错误,无奈之下只好使用老方法。有知道为何的朋友若能告知,感激不尽。
listAdapter = new SimpleCursorAdapter(this, R.layout.list_item, cursor, from, to);
listView.setAdapter(listAdapter);
listView.setTextFilterEnabled(true);

//设置listview点击事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
Cursor c = listAdapter.getCursor();
c.moveToPosition(position);
Intent intent = new Intent(MainActivity.this, ModifyActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("position", position);
intent.putExtras(bundle);
startActivity(intent);
}
});
//设置listview长按事件
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, final int position, long l) {
new AlertDialog.Builder(MainActivity.this)
.setTitle("是否删除该联系人?")
.setNegativeButton("取消", null)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
;
Cursor c = listAdapter.getCursor();
c.moveToPosition(position);
int itemID = c.getInt(c.getColumnIndex("_id"));
String[] which = new String[]{itemID + ""};
dbWrite.delete(TBL_NAME, "_id=?", which);
refreshListView();
}
}).show();

return true;
}
});
BirthRemind();

}

public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_add:
Intent intent = new Intent(MainActivity.this,addActivity.class);
startActivity(intent);
//                break;
//            case R.id.action_about:
//                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
//                builder.setTitle("关于我们")
//                        .setMessage("团队:Espirit\n"+"Blog:http://blog.csdn.net/qq_28625603")
//                        .show();
}
return super.onOptionsItemSelected(item);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}

public void refreshListView(){
cursor = dbRead.query(TBL_NAME, null, null, null, null, null, null);
listAdapter.changeCursor(cursor);

}

@Override
protected void onResume(){
super.onResume();
refreshListView();
}

//生日提醒功能
protected void BirthRemind(){
//获取当前时间
Calendar c = Calendar.getInstance();
int  month =c.get(Calendar.MONTH)+1;
int  day =c.get(Calendar.DAY_OF_MONTH);

Cursor cursor = dbWrite.query(TBL_NAME, new String[]{"month", "day"}, null, null, null, null, null);
//这里就是强烈建议大家用data型存储日期的原因。我利用四个List才确定了日期。如果处理大一点的数据,不敢想象。当初建表的时候没考虑周全,果然还是naive。
//主要逻辑就是先把所有人的生日月份拿出来和当前月比较,把相同的月份的索引拿出来放入新的list里。由于月和日是一起录入到两个list里的,所以索引是能对上号的。然后根据索引读取存放所有人的day里的数据,放在心的list里,最后如果list里有符合当前日的元素,就利用通知栏通知。
//因为建表的问题和时间关系,并没有读取姓名并且显示到通知栏上,实现起来相信也不难。这里点击通知栏也只有回到主页面而不是详情页。
List<Integer> listmonth = new ArrayList<Integer>();
List<Integer> listday = new ArrayList<Integer>();
while(cursor.moveToNext()){
listmonth.add(Integer.parseInt(cursor.getString(cursor.getColumnIndex("month"))));
listday.add( Integer.parseInt(cursor.getString(cursor.getColumnIndex("day"))));
}
int lm = listmonth.size();
List<Integer> matchm = new ArrayList<>();
for(int i = 0;i<lm;i++)
{
if(listmonth.get(i)==month){
matchm.add(i);
continue;
}
}
int mm = matchm.size();
List<Integer> matchd = new ArrayList<>();
for(int i=0; i<mm;i++){
matchd.add(listday.get(matchm.get(i)));
}

if(matchd.contains(day)){
//通知栏通知
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
int icon = android.R.drawable.stat_notify_chat;
long when = System.currentTimeMillis() + 2000;
Notification n = new Notification(icon, "您有一个联系人今天生日", when);
n.defaults = Notification.DEFAULT_SOUND;
n.flags |= Notification.FLAG_AUTO_CANCEL;

Intent openintent = new Intent(this,MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, openintent, PendingIntent.FLAG_CANCEL_CURRENT);
n.setLatestEventInfo(this, "生日提醒", "XXX今天生日,快去给TA送上祝福吧", pi);
nm.notify(0, n);
}

}

}


layout文件就不放了。

效果如下:

主页面,点击添加跳转至添加联系人页面。点击用户名跳转至联系人详情页,长按用户名呼出删除提示。



添加联系人页面。



删除提示框,点击确认即可删除用户。



在详情页点击修改可修改,单击电话或者短信图标分别对应通话或短信功能。



点击搜索框跳转到搜索页面。搜索页面也可以进入详情页和进行删除联系人操作。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息