手机联系人的信息在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; }
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>
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; } } }
最后,在向导界面三的代码中实现打开“选择联系人对话框”的逻辑即可:
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" />