好了,电话来去电的显示功能完成了,接下来就是对本地通讯录的数据抓取与同步的功能,在同步的方面我只做到了一半就是自定义数据库与本地数据库的同步,反向的则有些麻烦,还需要一段时间的研究。
开始吧。在上文中有一个自定义类是UserInfo,把他当做我们自定义数据库的单个数据:
// id
private int _id;
// 名字
private String name;
// 号码
private String phoneNum;
// 部门
private String department;
// 具体职位
private String job;
这是里面的所需要的数据库的列。根据这个是用SQLiteOpenHelper来继承并创建数据库,在创建一个DBUtils类来对该自定义联系人数据库进行增,删, 改,查。这是对自定义数据库的创建与操作的两个类。
SQLiteOpenHelper------->create table booklist(_id integer primary key autoincrement,name,phonenum,department,job)
还有一个是对本地联系人数据库的增,删,改的操作的类(DBPhoneUtils)。
另外在该程序第一次进入的时候需要导入本地联系人数据库。于是代码如下:
public static void getSystemContacts(Context context, DBUtils dbUtils) {
UserInfo userInfo = null;
String contactsID;
Cursor cursor = context.getContentResolver().query(phoneUris[0], null, null, null,
null);
while (cursor.moveToNext()) {
userInfo = new UserInfo();
contactsID = cursor.getString(cursor
.getColumnIndex(ContactsContract.Contacts._ID));
String userName = cursor.getString(cursor
.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
userInfo.setName(userName);
Cursor cursor2 = context.getContentResolver().query(
phoneUris[1],
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "="
+ contactsID, null, null);
while (cursor2.moveToNext()) {
String userPhone = cursor2
.getString(cursor2
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
userInfo.setPhoneNum(userPhone);
}
cursor2.close();
// 添加到自己的数据库中
dbUtils.insertData(userInfo.getName(), userInfo.getPhoneNum(),
null, null);
}
}
在第一次没有发现自定义数据库的时候导入本地联系人数据库。
结束后需要把自定义联系人数据库的内容使用listview来展示:
listView = (ListView) findViewById(R.id.listview);
// 游标适配器初始化
cursorAdapter = new SimpleCursorAdapter(this, R.layout.activity_item,
dbUtils.getCursor(), new String[] { "name", "phonenum" },
new int[] { R.id.userName, R.id.userPhone },
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
listView.setAdapter(cursorAdapter)
使用游标适配器很好的与数据库结合使用,速度更快。而DBUtils是一个对自定义联系人数据库的帮助类,但是数据量太大,我们一点点来讲:
// 得到数据库的起始游标
public Cursor getCursor() {
Cursor cursor = bookListDB.getReadableDatabase().query("booklist",
null, null, null, null, null, null);
return cursor;
}
这是得到自定义联系人数据库的起始游标,然后使用SimpleCursorAdapter来展示。
我的整个实现代码思想是这样的,现对自定义数据库进行处理(增删改查),然后同时对本地数据库进行处理(增删改)。所达成同步效果,所以整体是以 主函数 --> 嵌套 --> 自定义数据库 --> 嵌套 --> 本地数据库 来进行处理。
在对自定义数据库帮助类的创建与处理上使用了单例(DBUtils代码如下):
public class DBUtils {
private BookListDB bookListDB;
private Context context;
private static DBUtils dbUtils;
private DBPhoneUtils dbPhoneUtils;
public DBUtils(Context context) {
bookListDB = new BookListDB(context);
dbPhoneUtils = new DBPhoneUtils(context);
this.context = context;
}
public static DBUtils getInstance(Context context) {
if (dbUtils == null) {
dbUtils = new DBUtils(context);
}
return dbUtils;
}
// 添加数据
public void insertData(String name, String phonenum,
String department, String job) {
SQLiteDatabase dbDatabase = bookListDB.getReadableDatabase();
// 添加自定义数据库信息
if (!TextUtils.isEmpty(department) && !TextUtils.isEmpty(job)) {
dbDatabase
.execSQL(
"insert into booklist(name,phonenum,department,job) values(?,?,?,?)",
new Object[] { name, phonenum, department, job });
} else {
dbDatabase
.execSQL(
"insert into booklist(name,phonenum,department,job) values(?,?,?,?)",
new Object[] { name, phonenum, "未填写", "未填写" });
}
// 添加手机数据库信息
dbPhoneUtils.insertPhone(name, phonenum);
dbDatabase.close();
}
// 修改数据
public void updateData(String oldName, int _id, String name, String phonenum,
String department, String job) {
SQLiteDatabase dbDatabase = bookListDB.getReadableDatabase();
ContentValues values = new ContentValues();
values.put("name", name);
values.put("phonenum", phonenum);
values.put("department", department);
values.put("job", job);
// 修改自定义数据库信息
dbDatabase.update("booklist", values, "_id=?", new String[]{_id+""});
// 修改手机数据库信息
dbPhoneUtils.updatePhone(oldName, name, phonenum);
dbDatabase.close();
}
// 删除数据
public void delData(int _id, String name) {
SQLiteDatabase dbDatabase = bookListDB.getReadableDatabase();
// 删除自定义数据库信息
dbDatabase.delete("booklist", "_id=?", new String[]{_id+""});
// 删除手机数据库信息
dbPhoneUtils.deletePhone(name);
dbDatabase.close();
}
// 查询数据
public UserInfo selectInfo(String phoneNum) {
UserInfo userInfo = null;
SQLiteDatabase dbDatabase = bookListDB.getReadableDatabase();
Cursor cursor = dbDatabase.query("booklist", null, "phonenum = ?",
new String[] { phoneNum }, null, null, null);
if (cursor == null) {
} else {
if (cursor.moveToFirst()) {
userInfo = new UserInfo();
userInfo.set_id(cursor.getInt(cursor.getColumnIndex("_id")));
userInfo.setName(cursor.getString(cursor.getColumnIndex("name")));
userInfo.setPhoneNum(cursor.getString(cursor
.getColumnIndex("phonenum")));
userInfo.setDepartment(cursor.getString(cursor
.getColumnIndex("department")));
userInfo.setJob(cursor.getString(cursor.getColumnIndex("job")));
} else {
Toast.makeText(context, "数据不存在", Toast.LENGTH_SHORT).show();
}
}
cursor.close();
dbDatabase.close();
return userInfo;
}
// 得到数据库的起始游标
public Cursor getCursor() {
Cursor cursor = bookListDB.getReadableDatabase().query("booklist",
null, null, null, null, null, null);
return cursor;
}
// 得到通讯录总人数
public int getCount() {
Cursor cursor = bookListDB.getReadableDatabase().query("booklist",
null, null, null, null, null, null);
int count = cursor.getCount();
cursor.close();
return count;
}
}
其中在一些判断上只是为了保证用户输入的完整性,所以没什么太大用处。最后是在打开游标,数据库的时候要及时关闭以保证内存及时释放减少消耗。另外在几条代码中会有添加手机数据库等等注释就是为了同步本地数据库的方法:
public class DBPhoneUtils {
private Context context;
public DBPhoneUtils(Context context) {
this.context = context;
}
// 增
public void insertPhone(String name, String phoneNum) {
try {
ContentValues values = new ContentValues();
// 下面的操作会根据RawContacts表中已有的rawContactId使用情况自动生成新联系人的rawContactId
Uri rawContactUri = context.getContentResolver().insert(
RawContacts.CONTENT_URI, values);
long rawContactId = ContentUris.parseId(rawContactUri);
// 向data表插入姓名数据
if (name != "") {
values.clear();
values.put(Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
values.put(StructuredName.GIVEN_NAME, name);
context.getContentResolver().insert(
ContactsContract.Data.CONTENT_URI, values);
}
// 向data表插入电话数据
if (phoneNum != "") {
values.clear();
values.put(Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
values.put(Phone.NUMBER, phoneNum);
values.put(Phone.TYPE, Phone.TYPE_MOBILE);
context.getContentResolver().insert(
ContactsContract.Data.CONTENT_URI, values);
}
// 向data表插入Email数据
// if (work_email != "") {
// values.clear();
// values.put(Data.RAW_CONTACT_ID, rawContactId);
// values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
// values.put(Email.DATA, work_email);
// values.put(Email.TYPE, Email.TYPE_WORK);
// context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI,
// values);
// }
// 向data表插入QQ数据
// if (im_qq != "") {
// values.clear();
// values.put(Data.RAW_CONTACT_ID, rawContactId);
// values.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
// values.put(Im.DATA, im_qq);
// values.put(Im.PROTOCOL, Im.PROTOCOL_QQ);
// context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI,
// values);
// }
// 向data表插入头像数据
// Bitmap sourceBitmap =
// BitmapFactory.decodeResource(context.getResources(),
// R.drawable.icon);
// final ByteArrayOutputStream os = new ByteArrayOutputStream();
// // 将Bitmap压缩成PNG编码,质量为100%存储
// sourceBitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
// byte[] avatar = os.toByteArray();
// values.put(Data.RAW_CONTACT_ID, rawContactId);
// values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
// values.put(Photo.PHOTO, avatar);
// context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI,
// values);
}
catch (Exception e) {
}
}
// 删
public void deletePhone(String name) {
// 根据姓名求id
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(uri, new String[] { Data._ID },
"display_name=?", new String[] { name }, null);
if (cursor.moveToFirst()) {
int id = cursor.getInt(0);
// 根据id删除data中的相应数据
resolver.delete(uri, "display_name=?", new String[] { name });
uri = Uri.parse("content://com.android.contacts/data");
resolver.delete(uri, "raw_contact_id=?", new String[] { id + "" });
}
}
// 改
public void updatePhone(String oldName, String newName, String newPhoneNum) {
// 根据姓名求id
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(uri, new String[] { Data._ID },
"display_name=?", new String[] { oldName }, null);
if (cursor.moveToFirst()) {
int id = cursor.getInt(0);
Uri uri2 = Uri.parse("content://com.android.contacts/data");// 对data表的所有数据操作
// 修改电话
ContentValues values = new ContentValues();
values.put("data1", newPhoneNum);
context.getContentResolver()
.update(uri2,
values,
"mimetype=? and raw_contact_id=?",
new String[] { "vnd.android.cursor.item/phone_v2",
id + "" });
// 修改姓名
values.clear();
values = new ContentValues();
values.put("data1", newName);
context.getContentResolver().update(uri2, values,
"mimetype=? and raw_contact_id=?",
new String[] { "vnd.android.cursor.item/name", id + "" });
}
}
// 查
public void selectPhone() {
}
}
这是对本地数据库的增删改的帮助类。
而作为这个程序的其实位置MainActivity我使用上下文的方法按住跳出dialog框来对数据库的增删改查以及打电话。这个代码量就太大了(Dialog):
// 列表中点击的id及该界面
private View views;
// 上下文菜单
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
getMenuInflater().inflate(R.menu.menu_context_item, menu);
AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
views = acmi.targetView;
}
// 数据增删改处理
@Override
public boolean onContextItemSelected(MenuItem item) {
// 得到位置id
int id = item.getItemId();
// 图片所有内容初始化
View view = View.inflate(this, R.layout.window_add, null);
final EditText nameEditText = (EditText) view
.findViewById(R.id.add_name);
final EditText phonenumEditText = (EditText) view
.findViewById(R.id.add_phonenum);
final EditText departmentEditText = (EditText) view
.findViewById(R.id.add_department);
final EditText jobEditText = (EditText) view.findViewById(R.id.add_job);
// 上下文点击位置
TextView textView = (TextView) views.findViewById(R.id.userPhone);
// 修改前将原有数据放置上去, 并通过其_Id来修改用户数据
userInfo = dbUtils.selectInfo(textView.getText().toString() + "");
switch (id) {
case R.id.insert:
// 弹出增添联系人框
AlertDialog alertDialog = new AlertDialog.Builder(this)
.setTitle("增加联系人").setView(view)
.setPositiveButton("增加", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String nameString = nameEditText.getText()
.toString();
String phonenumString = phonenumEditText.getText()
.toString();
String departmentString = departmentEditText
.getText().toString();
String jobString = jobEditText.getText().toString();
if (!TextUtils.isEmpty(nameString)
&& !TextUtils.isEmpty(phonenumString)
&& !TextUtils.isEmpty(departmentString)
&& !TextUtils.isEmpty(jobString)) {
// 数据库添加
dbUtils.insertData(nameString, phonenumString,
departmentString, jobString);
} else if (TextUtils.isEmpty(departmentString)
|| TextUtils.isEmpty(jobString)) {
// 数据库添加
dbUtils.insertData(nameString, phonenumString,
null, null);
} else {
// 数据未填写完整提示
Toast.makeText(MainActivity.this, "请填写完整",
Toast.LENGTH_SHORT).show();
}
// 刷新列表
cursorAdapter.changeCursor(dbUtils.getCursor());
}
}).setNegativeButton("取消", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).create();
alertDialog.show();
break;
case R.id.update:
nameEditText.setText(userInfo.getName());
phonenumEditText.setText(userInfo.getPhoneNum());
departmentEditText.setText(userInfo.getDepartment());
jobEditText.setText(userInfo.getJob());
// 弹出修改联系人框
AlertDialog alertDialog2 = new AlertDialog.Builder(this)
.setTitle("修改联系人").setView(view)
.setPositiveButton("修改", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 用户输入数据
String nameString = nameEditText.getText()
.toString();
String phonenumString = phonenumEditText.getText()
.toString();
String departmentString = departmentEditText
.getText().toString();
String jobString = jobEditText.getText().toString();
if (!TextUtils.isEmpty(nameString)
&& !TextUtils.isEmpty(phonenumString)
&& !TextUtils.isEmpty(departmentString)
&& !TextUtils.isEmpty(jobString)) {
// 数据库修改
dbUtils.updateData(userInfo.getName(), userInfo.get_id(),
nameString, phonenumString,
departmentString, jobString);
} else {
// 数据未填写完整提示
Toast.makeText(MainActivity.this, "请填写完整",
Toast.LENGTH_SHORT).show();
}
// 刷新列表
cursorAdapter.changeCursor(dbUtils.getCursor());
}
}).setNegativeButton("取消", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).create();
alertDialog2.show();
break;
case R.id.delet:
AlertDialog alertDialog3 = new AlertDialog.Builder(this)
.setTitle("删除联系人")
.setMessage("是否删除联系人:
" + userInfo.getName())
.setPositiveButton("删除", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 数据库删除
dbUtils.delData(userInfo.get_id(), userInfo.getName());
// 刷新列表
cursorAdapter.changeCursor(dbUtils.getCursor());
}
}).setNegativeButton("取消", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).create();
alertDialog3.show();
break;
case R.id.select:
AlertDialog alertDialog4 = new AlertDialog.Builder(this)
.setTitle("联系人:" + userInfo.getName())
.setMessage(
"姓名:" + userInfo.getName() + "
电话:"
+ userInfo.getPhoneNum() + "
部门:"
+ userInfo.getDepartment() + "
职位:"
+ userInfo.getJob())
.setPositiveButton("拨打电话", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:"
+ userInfo.getPhoneNum()));
startActivity(intent);
}
}).setNegativeButton("关闭", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).create();
alertDialog4.show();
break;
}
return super.onContextItemSelected(item);
}
在结束整个程序后发现有很多不好的方法,比如可以使用本地数据库的ID导入到自定义数据库,这样可以在后续的处理中可以调用这个ID来直接处理本地数据库而不需要通过名字来找到ID在对该ID来处理本地数据库了。还有就是SIM卡和手机本地的区分,要往里面走的话就很多很多要学习的了,技术不佳..............
有任何建议,意见,及帮助请留言,相互学习!!!