自制的通讯录APP(SQLite的应用)
2016-06-28 00:39
1006 查看
转载请附上本文链接并标明作者。
这几天做了一个通讯录APP,主要难点是自己在SQlite建表而不是读取手机联系人的信息以及对SearchView的应用,另外还添加了生日提醒功能,由于时间关系并没有太多注释,可读性一般,也相对粗糙。建议在了解SQliteOpenHelper,Cursor,SimpleCursorAdapter,ListView和adapter等知识之后阅读,会容易理解。适合练手,有什么问题请留言指正,欢迎大牛指点。
(SDK:4.3,开发工具:AS1.5)
1.建立一个ContactDBhelper继承自SQliteOpenHelper类
2.点击添加进入addActivity来添加用户,主要用到了ContentValues.put方法。
3.点击ListView上的用户名跳转到ModifyActivity,详情页的概念。点击修改可以修改联系人信息,并单击完成保存,原理是用update更新表。
4.自定义Myadapter用于SearchView。
5.实现搜索框的方法是:点击EditText跳转到SearchActivity,利用SearchActivity里的SearchView来实现。此时就需要实例化前面自定义的Myadapter类。
6.最后是主活动。长按LiteView上的Item先弹出是否删除的对话框,选择是删除。删除主要靠delete()方法。
layout文件就不放了。
效果如下:
主页面,点击添加跳转至添加联系人页面。点击用户名跳转至联系人详情页,长按用户名呼出删除提示。
添加联系人页面。
删除提示框,点击确认即可删除用户。
在详情页点击修改可修改,单击电话或者短信图标分别对应通话或短信功能。
点击搜索框跳转到搜索页面。搜索页面也可以进入详情页和进行删除联系人操作。
这几天做了一个通讯录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文件就不放了。
效果如下:
主页面,点击添加跳转至添加联系人页面。点击用户名跳转至联系人详情页,长按用户名呼出删除提示。
添加联系人页面。
删除提示框,点击确认即可删除用户。
在详情页点击修改可修改,单击电话或者短信图标分别对应通话或短信功能。
点击搜索框跳转到搜索页面。搜索页面也可以进入详情页和进行删除联系人操作。
相关文章推荐
- 完美实现Android ListView中的TextView的跑马灯效果
- 个人信息安全报告发布:有 APP 每分钟调用位置权限 1468 次
- 下载量超过一亿的流行应用被发现含有恶意模块
- android上改变listView的选中颜色
- 苹果与Siri的七年之痒:“宫斗”戏码不断上演
- SQLite教程(十一):临时文件
- SQLite中重置自动编号列的方法
- Delphi7中Listview的常用功能汇总
- Delphi控件ListView的属性及使用方法详解
- 保护你的Sqlite数据库(SQLite数据库安全秘籍)
- SQLite教程(十):内存数据库和临时数据库
- SQLite 入门教程二 SQLite的创建、修改、删除表
- 详解SQLite中的数据类型
- 详解SQLite中的查询规划器
- C#封装的Sqlite访问类实例
- SQLite中的B-Tree实现细节分析
- SQLite 中文指南之FAQ第1/6页
- Android ListView弹性效果的实现方法
- APP添加CNZZ统计插件教程 Android版添加phonegap
- android中ListView数据刷新时的同步方法