手机联系人的信息在data/data/com.android.providers.contacts/databases/contacts2.db数据库中,使用“SQLiteExpert”查看(使用“SQLite+Database+Browser”查看不了)。
读取联系人信息的几个相关表:raw_contacts,data,mimetypes。
读取方式:raw_contacts表中读取contact_id字段
如上图一共两条记录,contact_id分别为1、2.
contact_id值对应data表中的raw_contact_id,查询出mimetype_id和data1、data2、……:
如上图一个raw_contact_id对应两条记录,mimetype_id分别为5和7,为什么是两条记录?因为一条记录名称相关,一条记录号码相关,如何区分呢?就是靠mimetype_id,通过mimetype_id查询mimetypes表来得知:
mimetype_id为5的类型为vnd.android.cursor.item/phone_v2表示电话号码,mimetype_id为7的类型为vnd.android.cursor.item/name表示名称。
通过以上分析便可以知道如何获取联系人的名称和号码了,首先定义一个结构体(C++习惯了,这里就是类)ContactInfo来表示联系人信息,一共两个字段,一个保存名称一个保存号码:
private String name;
private String phone;
在ContactInfo类的大括号里按ALT+Insert,选择生成“Getter and Setter”,在弹出的对话框中同时选择name和phone为它们自动构造getter和setter:
自动完成的代码:
package com.example.mobilesafe.engine;
/**
* Created by sing on 13-12-30.
* desc:
*/
public class ContactInfo {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
private String name;
private String phone;
}
编写一个ContactinfoProvider类用来获取联系人列表:
package com.example.mobilesafe.engine;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import com.example.mobilesafe.engine.ContactInfo;
import java.util.ArrayList;
import java.util.List;
/**
* Created by sing on 13-12-30.
* desc:
*/
public class ContactinfoProvider {
private Context context;
public ContactinfoProvider(Context context) {
this.context = context;
}
public List<ContactInfo> getContactInfos() {
List<ContactInfo> infos = new ArrayList<ContactInfo>();
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri datauri = Uri.parse("content://com.android.contacts/data");
Cursor cursor = context.getContentResolver().query(uri, new String[]{"contact_id"}, null, null, null);
while (cursor.moveToNext()) {
String id = cursor.getString(0);
ContactInfo info=new ContactInfo();
Cursor dataCursor = context.getContentResolver().query(datauri, null, "raw_contact_id=?", new String[]{id}, null);
while (dataCursor.moveToNext()) {
if (dataCursor.getString(dataCursor.getColumnIndex("mimetype")).equals("vnd.android.cursor.item/name")) {
info.setName(dataCursor.getString(dataCursor.getColumnIndex("data1")));
}else if (dataCursor.getString(dataCursor.getColumnIndex("mimetype")).equals("vnd.android.cursor.item/phone_v2")) {
info.setPhone(dataCursor.getString(dataCursor.getColumnIndex("data1")));
}
}
infos.add(info);
info = null;
dataCursor.close();
}
cursor.close();
return infos;
}
}
选择联系人界面设计:
布局为一个TextView显示标题,一个分割条,一个ListView显示联系人列表,使用之前设计的样式之后的布局文件为:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView style="@style/title_center_text"
android:text="选择联系人" />
<View style="@style/splitter_view"/>
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/lv_select_contact"
android:layout_gravity="center_horizontal" />
</LinearLayout>
SelectContactActivity.java代码:
package com.example.mobilesafe;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.example.mobilesafe.engine.ContactInfo;
import com.example.mobilesafe.engine.ContactinfoProvider;
import java.util.List;
/**
* Created by sing on 13-12-30.
* desc:
*/
public class SelectContactActivity extends Activity {
private ListView lv_select_contact;
private ContactinfoProvider provider;
private List<ContactInfo> infos;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.selectcontactactivity_layout);
lv_select_contact = (ListView) findViewById(R.id.lv_select_contact);
provider = new ContactinfoProvider(this);
infos = provider.getContactInfos();
lv_select_contact.setAdapter(new ContactAdapter());
lv_select_contact.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
ContactInfo info = (ContactInfo) lv_select_contact.getItemAtPosition(i);
String number = info.getPhone();
Intent data = new Intent();
data.putExtra("number", number);
setResult(0, data);
finish();
}
});
}
private class ContactAdapter extends BaseAdapter {
@Override
public int getCount() {
return infos.size();
}
@Override
public Object getItem(int i) {
return infos.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ContactInfo info = infos.get(i);
TextView tv = new TextView(getApplicationContext());
tv.setTextSize(24);
tv.setTextColor(Color.WHITE);
tv.setText(info.getName() + "\n" + info.getPhone());
return tv;
}
}
}
小技巧:ContactAdapter派生自BaseAdapter,必须要需要重载几个函数,可以在ContactAdapter类的大括号内按CTRL+O,在打开的对话框中选择必须重载的几个函数即可自动生成代码框架:
最后,在向导界面三的代码中实现打开“选择联系人对话框”的逻辑即可:
package com.example.mobilesafe;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.EditText;
import android.widget.Toast;
/**
* Created by sing on 13-12-26.
* desc:
*/
public class LostProtectStep3Activity extends Activity {
//输入安全号码的编辑框
private EditText et_step3_number;
private SharedPreferences sp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lostprotected_step3);
//读取配置,如果已经设置过安全号码则显示出来,否则设置hint
sp = getSharedPreferences("config", MODE_PRIVATE);
et_step3_number = (EditText) findViewById(R.id.et_step3_number);
String number = sp.getString("safenumber", "");
if (number.isEmpty()) {
et_step3_number.setHint("请输入安全号码或者选择一个号码");
} else {
et_step3_number.setText(number);
}
}
//上一步按钮的处理过程,显示第二个向导页面
public void prev(android.view.View view) {
Intent intent = new Intent(this, LostProtectStep2Activity.class);
startActivity(intent);
finish();
overridePendingTransition(R.anim.rightshowleftin, R.anim.rightshowleftout);
}
//下一步按钮的处理过程,将设置的安全号码保存到配置文件,并显示第四个向导页面
public void next(android.view.View view) {
String number = et_step3_number.getText().toString().trim();
if (number.isEmpty()) {
Toast.makeText(this, "安全号码不能为空", 0).show();
return;
}
//将设置的安全号码保存到配置文件
SharedPreferences.Editor editor = sp.edit();
editor.putString("safenumber", number);
editor.commit();
//显示第四个向导页面
Intent intent = new Intent(this, LostProtectStep4Activity.class);
startActivity(intent);
finish();
overridePendingTransition(R.anim.leftshowrigthin, R.anim.leftshowrigthout);
}
//按钮“选择联系人”的处理事件
public void selectContact(android.view.View view) {
Intent intent = new Intent(this, SelectContactActivity.class);
startActivityForResult(intent, 0);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (data != null) {
//获取选择的联系人号码
String number = data.getStringExtra("number");
et_step3_number.setText(number);
}
super.onActivityResult(requestCode, resultCode, data);
}
}
读取联系人信息需要添加权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />