第三部分 通讯录  


该例实现了浏览联系人、添加联系人、删除联系人、编辑联系人、查看联系人,当找到一个联系人后,可以呼叫或者发送消息给该联系人。  


下例体现了UI设计、数据库的综合操作、动态菜单的使用以及各种权限的注册。  



 public class ContactColumn implements BaseColumns{//定义数据,要设计数据库,首先要确定数据都是什么内容,为了方便管理、维护和共享首先将数据中要使用的数据全部定义到 

 ContactColumn类 

 public ContactColumn(){ 

 } 

 //列名 

 public static final String NAME = "name";//姓名 

 public static final String MOBILENUM = "mobileNumber";//移动电话 

 public static final String HOMENUM = "homeNumber";//家庭电话 

 public static final String ADDRESS = "address";//地址 

 public static final String EMAIL = "email";//邮箱 

 public static final String BLOG = "blog";//博客 

 //列 索引值 

 public static final int _ID_COLUMN = 0; 

 public static final int NAME_COLUMN = 1; 

 public static final int MOBILENUM_COLUMN = 2; 

 public static final int HOMENUM_COLUMN = 3; 

 public static final int ADDRESS_COLUMN = 4; 

 public static final int EMAIL_COLUMN = 5; 

 public static final int BLOG_COLUMN = 6; 

 public static final String[] PROJECTION ={//查询结果 

 _ID, 

 NAME, 

 MOBILENUM, 

 HOMENUM, 

 ADDRESS, 

 EMAIL, 

 BLOG, 

 }; 

 } 
public class DBHelper extends SQLiteOpenHelper{//android.database.sqlite.SQLiteOpenHelper类是一个专门用于数据库创建和版本管理的辅助类。
 此处创建了一个DBHelper类来维护和更新数据库
 public static final String DATABASE_NAME = "mycontacts.db";//数据库名
 public static final int DATABASE_VERSION = 2; //版本
 public static final String CONTACTS_TABLE = "contacts"; //表名
 //创建表
 private static final String DATABASE_CREATE = 
 "CREATE TABLE " + CONTACTS_TABLE +" ("
 + ContactColumn._ID+" integer primary key autoincrement,"
 + ContactColumn.NAME+" text,"
 + ContactColumn.MOBILENUM+" text,"
 + ContactColumn.HOMENUM+" text,"
 + ContactColumn.ADDRESS+" text,"
 + ContactColumn.EMAIL+" text,"
 + ContactColumn.BLOG+" text);";
 public DBHelper(Context context){
 super(context, DATABASE_NAME, null, DATABASE_VERSION);
 }
 public void onCreate(SQLiteDatabase db){
 db.execSQL(DATABASE_CREATE);
 }
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
 db.execSQL("DROP TABLE IF EXISTS " + CONTACTS_TABLE);
 onCreate(db);
 }
 }public class ContactsProvider extends ContentProvider{//ContentProvider类提供了多个应用间数据共享的方式,比如:联系人信息可以被多个应用程序访问。
 ContentProvider是一个实现了一组用于提供其他应用程序存在数据的标准方法类。
 所以此处创建此类用来对数据库的操作,如:查询、修改、添加、删除
 private static final String TAG= "ContactsProvider"; 
 private DBHelper dbHelper;
 private SQLiteDatabase contactsDB;
 public static final String AUTHORITY = "com.yarin.android.provider.ContactsProvider";
 public static final String CONTACTS_TABLE = "contacts";
 public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"+CONTACTS_TABLE);
 //下面是自定义的类型
 public static final int CONTACTS = 1;
 public static final int CONTACT_ID = 2;
 private static final UriMatcher uriMatcher;
 static{
 uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
 uriMatcher.addURI(AUTHORITY,"contacts",CONTACTS);
 uriMatcher.addURI(AUTHORITY,"contacts/#",CONTACT_ID);//单独列
 }
 public boolean onCreate(){
 dbHelper = new DBHelper(getContext());
 //执行创建数据库
 contactsDB = dbHelper.getWritableDatabase();
 return (contactsDB == null) ? false : true;
 }
 public int delete(Uri uri, String where, String[] selectionArgs){// 删除指定数据列
 int count;
 switch (uriMatcher.match(uri)){
 case CONTACTS:
 count = contactsDB.delete(CONTACTS_TABLE, where, selectionArgs);
 break;
 case CONTACT_ID:
 String contactID = uri.getPathSegments().get(1);
 count = contactsDB.delete(CONTACTS_TABLE, ContactColumn._ID 
 + "=" + contactID 
 + (!TextUtils.isEmpty(where) ? " AND (" + where + ")" : ""),
 selectionArgs);
 break;
 default:
 throw new IllegalArgumentException("Unsupported URI: " + uri);
 }
 getContext().getContentResolver().notifyChange(uri, null);
 return count;
 }
 public String getType(Uri uri){// URI类型转换。我们定义了一个新的类型,因此得到URI时,就可以通过此方法转换成我们需要的类型。
 其中CONTACTS表示多行数据,CONTACT_ID表示单行数据。注意这些类型需要在AndroidManifest.xml中声明权限。
 switch (uriMatcher.match(uri)){
 case CONTACTS:
 return "vnd.android.cursor.dir/vnd.yarin.android.mycontacts";
 case CONTACT_ID:
 return "vnd.android.cursor.item/vnd.yarin.android.mycontacts";
 default:
 throw new IllegalArgumentException("Unsupported URI: " + uri);
 }
 }
 public Uri insert(Uri uri, ContentValues initialValues){// 插入数据
 if (uriMatcher.match(uri) != CONTACTS){
 throw new IllegalArgumentException("Unknown URI " + uri);
 }
 ContentValues values;
 if (initialValues != null){
 values = new ContentValues(initialValues);
 Log.e(TAG + "insert", "initialValues is not null");
 }else{
 values = new ContentValues();
 }
 // 设置默认值
 if (values.containsKey(ContactColumn.NAME) == false){
 values.put(ContactColumn.NAME, "");
 }
 if (values.containsKey(ContactColumn.MOBILENUM) == false){
 values.put(ContactColumn.MOBILENUM, "");
 }
 if (values.containsKey(ContactColumn.HOMENUM) == false){
 values.put(ContactColumn.HOMENUM, "");
 }
 if (values.containsKey(ContactColumn.ADDRESS) == false){
 values.put(ContactColumn.ADDRESS, "");
 }
 if (values.containsKey(ContactColumn.EMAIL) == false){
 values.put(ContactColumn.EMAIL, "");
 }
 if (values.containsKey(ContactColumn.BLOG) == false){
 values.put(ContactColumn.BLOG, "");
 }
 Log.e(TAG + "insert", values.toString());
 long rowId = contactsDB.insert(CONTACTS_TABLE, null, values);
 if (rowId > 0){
 Uri noteUri = ContentUris.withAppendedId(CONTENT_URI, rowId);
 getContext().getContentResolver().notifyChange(noteUri, null);
 Log.e(TAG + "insert", noteUri.toString());
 return noteUri;
 }
 throw new SQLException("Failed to insert row into " + uri);
 }
 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder){// 对数据库的操作,查询数据
 Log.e(TAG + ":query", " in Query");
 SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
 qb.setTables(CONTACTS_TABLE);
 switch (uriMatcher.match(uri)){
 case CONTACT_ID:
 qb.appendWhere(ContactColumn._ID + "=" + uri.getPathSegments().get(1));
 break;
 default:
 break;
 }
 String orderBy;
 if (TextUtils.isEmpty(sortOrder)){
 orderBy = ContactColumn._ID;
 }else{
 orderBy = sortOrder;
 }
 Cursor c = qb.query(contactsDB, projection, selection, selectionArgs, null, null, orderBy);
 c.setNotificationUri(getContext().getContentResolver(), uri);
 return c;
 }
 public int update(Uri uri, ContentValues values, String where, String[] selectionArgs){// 更新数据库
 int count;
 Log.e(TAG + "update", values.toString());
 Log.e(TAG + "update", uri.toString());
 Log.e(TAG + "update :match", "" + uriMatcher.match(uri));
 switch (uriMatcher.match(uri)){
 case CONTACTS:
 Log.e(TAG + "update", CONTACTS + "");
 count = contactsDB.update(CONTACTS_TABLE, values, where, selectionArgs);
 break;
 case CONTACT_ID:
 String contactID = uri.getPathSegments().get(1);
 Log.e(TAG + "update", contactID + "");
 count = contactsDB.update(CONTACTS_TABLE, values, ContactColumn._ID + "=" +
 contactID+ (!TextUtils.isEmpty(where) ? " AND (" + where + ")" : ""), selectionArgs);
 break;
 default:
 throw new IllegalArgumentException("Unsupported URI: " + uri);
 }
 getContext().getContentResolver().notifyChange(uri, null);
 return count;
 }
 }public class MyContacts extends ListActivity{//浏览联系人时,如果没有选中一条联系人,那么就不能使用删除、修改、查看等菜单。但是当选中一条数据时,就可以执行这些
 功能,所以我们要使用动态菜单,根据不同的状态显示不同的菜单。
 动态菜单要在Android中使用Intent来设置ACTION,然后根据不同的动作来启动不同的界面Activity
 private static final String TAG = "MyContacts";
 private static final int AddContact_ID = Menu.FIRST;
 private static final int EditContact_ID = Menu.FIRST+1;
 private static final int DELEContact_ID = Menu.FIRST+2;
 private static final int EXITContact_ID = Menu.FIRST+3;

 public void onCreate(Bundle savedInstanceState){
 super.onCreate(savedInstanceState);
 setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);

 Intent intent = getIntent();
 if (intent.getData() == null) {
 intent.setData(ContactsProvider.CONTENT_URI);
 }
 getListView().setOnCreateContextMenuListener(this);
 getListView().setBackgroundResource(R.drawable.bg);
 Cursor cursor = managedQuery(getIntent().getData(), ContactColumn.PROJECTION, null, null,null);
 //注册每个列表表示形式 :姓名 + 移动电话
 SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
 android.R.layout.simple_list_item_2,
 cursor,
 new String[] {ContactColumn.NAME, ContactColumn.MOBILENUM },
 new int[] { android.R.id.text1, android.R.id.text2 });
 setListAdapter(adapter);
 }
 public boolean onCreateOptionsMenu(Menu menu){//添加动态菜单"编辑","查看"的方法
 super.onCreateOptionsMenu(menu);
 //添加联系人
 menu.add(0, AddContact_ID, 0, R.string.add_user)
 .setShortcut('3', 'a')
 .setIcon(R.drawable.add);

 Intent intent = new Intent(null, getIntent().getData());
 intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
 menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0,new ComponentName(this, MyContacts.class), null, intent, 0, null);
 //退出程序
 menu.add(0, EXITContact_ID, 0, R.string.exit)
 .setShortcut('4', 'd')
 .setIcon(R.drawable.exit);
 return true;

 } 
 public boolean onOptionsItemSelected(MenuItem item) { //处理菜单操作
 switch (item.getItemId()) {
 case AddContact_ID: 
 startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData())); //添加联系人
 return true;
 case EXITContact_ID: 
 this.finish();//退出程序
 return true;
 }
 return super.onOptionsItemSelected(item);
 } 
 public boolean onPrepareOptionsMenu(Menu menu){
 super.onPrepareOptionsMenu(menu);
 final boolean haveItems = getListAdapter().getCount() > 0;
 if (haveItems){
 Uri uri = ContentUris.withAppendedId(getIntent().getData(), getSelectedItemId());
 Intent[] specifics = new Intent[2];
 specifics[0] = new Intent(Intent.ACTION_EDIT, uri);
 specifics[1] = new Intent(Intent.ACTION_VIEW, uri);
 MenuItem[] items = new MenuItem[2];
 //添加满足条件的菜单
 Intent intent = new Intent(null, uri);
 intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
 menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, specifics, intent, 0, items);
 if (items[0] != null){
 items[0].setShortcut('1', 'e').setIcon(R.drawable.edituser).setTitle(R.string.editor_user); //编辑联系人
 }
 if (items[1] != null){
 items[1].setShortcut('2', 'f').setTitle(R.string.view_user).setIcon(R.drawable.viewuser); //查看联系人
 }
 }else{
 menu.removeGroup(Menu.CATEGORY_ALTERNATIVE);
 }
 return true;
 } 
 protected void onListItemClick(ListView l, View v, int position, long id){ //动态菜单处理,点击的默认操作也可以在这里处理
 Uri uri = ContentUris.withAppendedId(getIntent().getData(), id); 
 String action = getIntent().getAction(); 
 if ( Intent.ACTION_EDIT.equals(action) ){
 startActivity(new Intent(Intent.ACTION_EDIT, uri)); //编辑联系人 
 }else{ 
 startActivity(new Intent(Intent.ACTION_VIEW, uri)); //查看联系人 
 } 
 } 
 public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo){ //长按触发的菜单。这时可以设置能够进行操作的菜单,通过 onContextItemSelected
 方法来监听长按菜单的事件处理。
 AdapterView.AdapterContextMenuInfo info;
 try{
 info = (AdapterView.AdapterContextMenuInfo) menuInfo;
 }catch (ClassCastException e){
 return;
 }
 Cursor cursor = (Cursor) getListAdapter().getItem(info.position);//得到长按的数据项
 if (cursor == null){
 return;
 }
 menu.setHeaderTitle(cursor.getString(1));
 menu.add(0, DELEContact_ID, 0, R.string.delete_user);//添加删除菜单
 }
 public boolean onContextItemSelected(MenuItem item){//本例中长按时会弹出删除该条记录的菜单
 AdapterView.AdapterContextMenuInfo info;
 try{
 info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
 }catch (ClassCastException e){
 return false;
 }
 switch (item.getItemId()){
 case DELEContact_ID:{
 //删除一条记录
 Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), info.id);
 getContentResolver().delete(noteUri, null, null);
 return true;
 }
 }
 return false;
 }
 }public class ContactEditor extends Activity{
 private static final String TAG = "ContactEditor";
 private static final int STATE_EDIT = 0;
 private static final int STATE_INSERT = 1; 
 private static final int REVERT_ID = Menu.FIRST;
 private static final int DISCARD_ID = Menu.FIRST + 1;
 private static final int DELETE_ID = Menu.FIRST + 2;

 private Cursor mCursor;
 private int mState;
 private Uri mUri;
 private EditText nameText;
 private EditText mobileText;
 private EditText homeText;
 private EditText addressText;
 private EditText emailText;
 private EditText blogText;

 private Button okButton;
 private Button cancelButton;

 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);final Intent intent = getIntent();
 final String action = intent.getAction();
 Log.e(TAG + ":onCreate", action);
 if (Intent.ACTION_EDIT.equals(action)){//根据action的不同进行不同的操作,编辑联系人
 mState = STATE_EDIT;
 mUri = intent.getData();
 }else if (Intent.ACTION_INSERT.equals(action)){
 //添加新联系人
 mState = STATE_INSERT;
 mUri = getContentResolver().insert(intent.getData(), null);
 if (mUri == null){
 Log.e(TAG + ":onCreate", "Failed to insert new Contact into " + getIntent().getData());
 finish();
 return;
 }
 setResult(RESULT_OK, (new Intent()).setAction(mUri.toString()));}else{
 Log.e(TAG + ":onCreate", " unknown action");
 finish();
 return;
 } 
 setContentView(R.layout.editorcontacts);

 nameText = (EditText) findViewById(R.id.EditText01);
 mobileText = (EditText) findViewById(R.id.EditText02);
 homeText = (EditText) findViewById(R.id.EditText03);
 addressText = (EditText) findViewById(R.id.EditText04);
 emailText = (EditText) findViewById(R.id.EditText05);
 blogText = (EditText) findViewById(R.id.EditText06);

 okButton = (Button)findViewById(R.id.Button01);
 cancelButton = (Button)findViewById(R.id.Button02);

 okButton.setOnClickListener(new OnClickListener(){
 public void onClick(View v) {
 String text = nameText.getText().toString();
 if(text.length()==0){
 //如果没有输入东西,则不添加记录
 setResult(RESULT_CANCELED);
 deleteContact();
 finish();
 }else{
 updateContact();//添加一条数据
 }
 }

 });
 cancelButton.setOnClickListener(new OnClickListener(){
 public void onClick(View v) {
 if(mState == STATE_INSERT){
 //不添加记录
 setResult(RESULT_CANCELED);
 deleteContact();
 finish();
 }else{
 backupContact();//恢复到编辑前的状态
 }
 }
 }); 
 Log.e(TAG+":onCreate", mUri.toString());
 // 获得并保存原始联系人信息
 mCursor = managedQuery(mUri, ContactColumn.PROJECTION, null, null, null);
 mCursor.moveToFirst();
 Log.e(TAG, "end of onCreate()");
 }
 protected void onResume(){
 super.onResume();
 if (mCursor != null){
 Log.e(TAG + ":onResume", "count:" + mCursor.getColumnCount());
 mCursor.moveToFirst();// 读取并显示联系人信息
 if (mState == STATE_EDIT){
 setTitle(getText(R.string.editor_user));
 }else if (mState == STATE_INSERT){
 setTitle(getText(R.string.add_user));
 }
 String name = mCursor.getString(ContactColumn.NAME_COLUMN);
 String moblie = mCursor.getString(ContactColumn.MOBILENUM_COLUMN);
 String home = mCursor.getString(ContactColumn.HOMENUM_COLUMN);
 String address = mCursor.getString(ContactColumn.ADDRESS_COLUMN);
 String email = mCursor.getString(ContactColumn.EMAIL_COLUMN);
 String blog = mCursor.getString(ContactColumn.BLOG_COLUMN);

 nameText.setText(name);
 mobileText.setText(moblie);
 homeText.setText(home);
 addressText.setText(address);
 emailText.setText(email);
 blogText.setText(blog);
 }else{
 setTitle("错误信息");
 }
 } 
 protected void onPause(){
 super.onPause();
 if (mCursor != null){
 String text = nameText.getText().toString();
 if (text.length() == 0){
 Log.e(TAG + ":onPause", "nameText is null ");
 setResult(RESULT_CANCELED);
 deleteContact();
 }else{// 更新信息
 ContentValues values = new ContentValues();
 values.put(ContactColumn.NAME, nameText.getText().toString());
 values.put(ContactColumn.MOBILENUM, mobileText.getText().toString());
 values.put(ContactColumn.HOMENUM, homeText.getText().toString());
 values.put(ContactColumn.ADDRESS, addressText.getText().toString());
 values.put(ContactColumn.EMAIL, emailText.getText().toString());
 values.put(ContactColumn.BLOG, blogText.getText().toString());

 Log.e(TAG + ":onPause", mUri.toString());
 Log.e(TAG + ":onPause", values.toString());
 getContentResolver().update(mUri, values, null, null);
 }
 }
 } 
 public boolean onCreateOptionsMenu(Menu menu) {
 super.onCreateOptionsMenu(menu);
 if (mState == STATE_EDIT) {
 menu.add(0, REVERT_ID, 0, R.string.revert)
 .setShortcut('0', 'r')
 .setIcon(R.drawable.listuser);
 menu.add(0, DELETE_ID, 0, R.string.delete_user)
 .setShortcut('0', 'f')
 .setIcon(R.drawable.remove);
 } else {
 menu.add(0, DISCARD_ID, 0, R.string.revert)
 .setShortcut('0', 'd')
 .setIcon(R.drawable.listuser);
 }
 return true;
 }
 public boolean onOptionsItemSelected(MenuItem item) {//菜单处理
 switch (item.getItemId()) {
 case DELETE_ID:
 deleteContact();
 finish();
 break;
 case DISCARD_ID:
 cancelContact();
 break;
 case REVERT_ID:
 backupContact();
 break;
 }
 return super.onOptionsItemSelected(item);
 }
 private void deleteContact() {//删除联系人信息
 if (mCursor != null) {
 mCursor.close();
 mCursor = null;
 getContentResolver().delete(mUri, null, null);
 nameText.setText("");
 }
 }
 private void cancelContact() {//丢弃信息
 if (mCursor != null) {
 deleteContact();
 }
 setResult(RESULT_CANCELED);
 finish();
 }
 private void updateContact() {//更新 变更的信息
 if (mCursor != null) {
 mCursor.close();
 mCursor = null;
 ContentValues values = new ContentValues();
 values.put(ContactColumn.NAME, nameText.getText().toString());
 values.put(ContactColumn.MOBILENUM, mobileText.getText().toString());
 values.put(ContactColumn.HOMENUM, homeText.getText().toString());
 values.put(ContactColumn.ADDRESS, addressText.getText().toString());
 values.put(ContactColumn.EMAIL, emailText.getText().toString());
 values.put(ContactColumn.BLOG, blogText.getText().toString());
 Log.e(TAG+":onPause",mUri.toString());
 Log.e(TAG+":onPause",values.toString());
 getContentResolver().update(mUri, values, null, null);
 }
 setResult(RESULT_CANCELED);
 finish();
 }
 private void backupContact() {//取消用,回退到最初的信息
 if (mCursor != null) {
 mCursor.close();
 mCursor = null;
 ContentValues values = new ContentValues();
 values.put(ContactColumn.NAME, nameText.getText().toString());
 values.put(ContactColumn.MOBILENUM, mobileText.getText().toString());
 values.put(ContactColumn.HOMENUM, homeText.getText().toString());
 values.put(ContactColumn.ADDRESS, addressText.getText().toString());
 values.put(ContactColumn.EMAIL, emailText.getText().toString());
 values.put(ContactColumn.BLOG, blogText.getText().toString());
 Log.e(TAG+":onPause",mUri.toString());
 Log.e(TAG+":onPause",values.toString());
 getContentResolver().update(mUri, values, null, null);
 }
 setResult(RESULT_CANCELED);
 finish();
 }
 }public class ContactView extends Activity{
 private TextView mTextViewName;
 private TextView mTextViewMobile;
 private TextView mTextViewHome;
 private TextView mTextViewAddress;
 private TextView mTextViewEmail;
 private TextView mTextViewBlog;

 private Cursor mCursor;
 private Uri mUri;

 private static final int REVERT_ID = Menu.FIRST;
 private static final int DELETE_ID = Menu.FIRST + 1;
 private static final int EDITOR_ID = Menu.FIRST + 2;
 private static final int CALL_ID = Menu.FIRST + 3;
 private static final int SENDSMS_ID = Menu.FIRST + 4;

 public void onCreate(Bundle savedInstanceState){
 super.onCreate(savedInstanceState);

 mUri = getIntent().getData();
 this.setContentView(R.layout.viewuser);

 mTextViewName = (TextView) findViewById(R.id.TextView_Name);
 mTextViewMobile = (TextView) findViewById(R.id.TextView_Mobile);
 mTextViewHome = (TextView) findViewById(R.id.TextView_Home);
 mTextViewAddress = (TextView) findViewById(R.id.TextView_Address);
 mTextViewEmail = (TextView) findViewById(R.id.TextView_Email);
 mTextViewBlog = (TextView) findViewById(R.id.TextView_Blog);

 mCursor = managedQuery(mUri, ContactColumn.PROJECTION, null, null, null); // 获得并保存原始联系人信息
 mCursor.moveToFirst();
 }
 protected void onResume(){
 super.onResume();
 if (mCursor != null){
 mCursor.moveToFirst();// 读取并显示联系人信息
 mTextViewName.setText(mCursor.getString(ContactColumn.NAME_COLUMN));
 mTextViewMobile.setText(mCursor.getString(ContactColumn.MOBILENUM_COLUMN));
 mTextViewHome.setText(mCursor.getString(ContactColumn.HOMENUM_COLUMN));
 mTextViewAddress.setText(mCursor.getString(ContactColumn.ADDRESS_COLUMN));
 mTextViewEmail.setText(mCursor.getString(ContactColumn.EMAIL_COLUMN));
 mTextViewBlog.setText(mCursor.getString(ContactColumn.BLOG_COLUMN));
 }else{
 setTitle("错误信息");
 }
 }
 public boolean onCreateOptionsMenu(Menu menu){
 super.onCreateOptionsMenu(menu);
 //添加菜单
 menu.add(0, REVERT_ID, 0, R.string.revert).setShortcut('0', 'r').setIcon(R.drawable.listuser);
 menu.add(0, DELETE_ID, 0, R.string.delete_user).setShortcut('0', 'd').setIcon(R.drawable.remove);
 menu.add(0, EDITOR_ID, 0, R.string.editor_user).setShortcut('0', 'd').setIcon(R.drawable.edituser);
 menu.add(0, CALL_ID, 0, R.string.call_user).setShortcut('0', 'd')
 .setIcon(R.drawable.calluser)
 .setTitle(this.getResources()
 .getString(R.string.call_user)+mTextViewName
 .getText());
 menu.add(0, SENDSMS_ID, 0, R.string.sendsms_user).setShortcut('0', 'd')
 .setIcon(R.drawable.sendsms)
 .setTitle(this.getResources()
 .getString(R.string.sendsms_user)+mTextViewName
 .getText());
 return true;
 }
 public boolean onOptionsItemSelected(MenuItem item){
 switch (item.getItemId()){
 case DELETE_ID:
 deleteContact();//删除
 finish();
 break;
 case REVERT_ID:
 setResult(RESULT_CANCELED);//返回列表
 finish();
 break;
 case EDITOR_ID:
 startActivity(new Intent(Intent.ACTION_EDIT, mUri)); //编辑联系人
 break;
 case CALL_ID:
 Intent call = new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+mTextViewMobile.getText()));//呼叫联系人
 startActivity(call);
 break;
 case SENDSMS_ID:
 Intent sms = new Intent(Intent.ACTION_SENDTO,Uri.parse("smsto:"+mTextViewMobile.getText()));//发短信给联系人
 startActivity(sms);
 break;
 }
 return super.onOptionsItemSelected(item);
 }
 private void deleteContact(){// 删除联系人信息
 if (mCursor != null){
 mCursor.close();
 mCursor = null;
 getContentResolver().delete(mUri, null, null);
 setResult(RESULT_CANCELED);
 }
 }
 }
 res.layout.eidtorcontacts.xml
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout 
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical" 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent"
 android:background="@drawable/bg">
 <TableRow 
 android:id="@+id/TableRow01" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content">
 <TextView 
 android:id="@+id/TextView01" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:text="@string/name" 
 android:textSize="16px"></TextView>
 <EditText 
 android:id="@+id/EditText01" 
 android:layout_height="wrap_content" 
 android:layout_width="fill_parent"/>
 </TableRow>
 <TableRow 
 android:id="@+id/TableRow02" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content">
 <TextView 
 android:id="@+id/TextView02" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:textSize="16px" 
 android:text="@string/mobile"></TextView>
 <EditText 
 android:id="@+id/EditText02" 
 android:layout_height="wrap_content" 
 android:layout_width="fill_parent"></EditText>
 </TableRow>
 <TableRow 
 android:id="@+id/TableRow03" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content">
 <TextView 
 android:id="@+id/TextView03" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:textSize="16px" 
 android:text="@string/home"></TextView>
 <EditText 
 android:id="@+id/EditText03" 
 android:layout_height="wrap_content" 
 android:layout_width="fill_parent"></EditText>
 </TableRow>
 <TableRow 
 android:id="@+id/TableRow04" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content">
 <TextView 
 android:id="@+id/TextView04" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:textSize="16px" 
 android:text="@string/address"></TextView>
 <EditText 
 android:id="@+id/EditText04" 
 android:layout_height="wrap_content" 
 android:layout_width="fill_parent"></EditText>
 </TableRow>
 <TableRow 
 android:id="@+id/TableRow05" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content">
 <TextView 
 android:id="@+id/TextView05" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:text="@string/email" 
 android:textSize="16px"></TextView>
 <EditText 
 android:id="@+id/EditText05" 
 android:layout_height="wrap_content" 
 android:layout_width="fill_parent"></EditText>
 </TableRow>
 <TableRow 
 android:id="@+id/TableRow06" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content">
 <TextView 
 android:id="@+id/TextView06" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:textSize="16px" 
 android:text="@string/blog"></TextView>
 <EditText 
 android:id="@+id/EditText06" 
 android:layout_height="wrap_content" 
 android:layout_width="fill_parent"></EditText>
 </TableRow>
 <TableRow 
 android:id="@+id/TableRow07" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content">
 <Button 
 android:id="@+id/Button01" 
 android:layout_height="wrap_content" 
 android:text="@string/ok" 
 android:textSize="16px" 
 android:layout_width="wrap_content">
 </Button>
 <Button 
 android:id="@+id/Button02" 
 android:layout_height="wrap_content" 
 android:text="@string/cancel" 
 android:textSize="16px" 
 android:layout_width="wrap_content">
 </Button>
 </TableRow>
 </LinearLayout>res.layout.viewuser.xml
 <?xml version="1.0" encoding="utf-8"?>
 <TableLayout 
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:stretchColumns="1"
 android:background="@drawable/bg">
 <TableRow>
 <TextView
 android:layout_column="1"
 android:text="查看联系人"
 android:textColor="#ff44f3ff"
 android:padding="15dip" />
 </TableRow>
 <View
 android:layout_height="3dip"
 android:background="#ffffffff" />
 <TableRow>
 <TextView
 android:layout_column="1"
 android:text="姓名:"
 android:textColor="#ffffaaaf"
 android:padding="10dip" />
 <TextView
 android:id="@+id/TextView_Name"
 android:textColor="#ffffaaaf"
 android:padding="10dip" />
 </TableRow>
 <View
 android:layout_height="1dip"
 android:background="#ffffffff" />
 <TableRow>
 <TextView
 android:layout_column="1"
 android:text="手机:"
 android:textColor="#ffffaaaf"
 android:padding="10dip" />
 <TextView
 android:id="@+id/TextView_Mobile"
 android:textColor="#ffffaaaf"
 android:padding="10dip" />
 </TableRow>
 <View
 android:layout_height="1dip"
 android:background="#ffffffff" />
 <TableRow>
 <TextView
 android:layout_column="1"
 android:text="座机:"
 android:textColor="#ffffaaaf"
 android:padding="10dip" />
 <TextView
 android:id="@+id/TextView_Home"
 android:textColor="#ffffaaaf"
 android:padding="10dip" />
 </TableRow>
 <View
 android:layout_height="1dip"
 android:background="#ffffffff" />
 <TableRow>
 <TextView
 android:layout_column="1"
 android:text="地址:"
 android:textColor="#ffffaaaf"
 android:padding="10dip" />
 <TextView
 android:id="@+id/TextView_Address"
 android:textColor="#ffffaaaf"
 android:padding="10dip" />
 </TableRow>
 <View
 android:layout_height="1dip"
 android:background="#ffffffff" />
 <TableRow>
 <TextView
 android:layout_column="1"
 android:text="邮箱:"
 android:textColor="#ffffaaaf"
 android:padding="10dip" />
 <TextView
 android:id="@+id/TextView_Email"
 android:textColor="#ffffaaaf"
 android:padding="10dip" />
 </TableRow>
 <View
 android:layout_height="1dip"
 android:background="#ffffffff" />
 <TableRow>
 <TextView
 android:layout_column="1"
 android:text="主页:"
 android:textColor="#ffffaaaf"
 android:padding="10dip" />
 <TextView
 android:id="@+id/TextView_Blog"
 android:textColor="#ffffaaaf"
 android:padding="10dip" />
 </TableRow>
 </TableLayout>AndroidManifest.xml//本例中代码中创建了新类型,也设置了呼叫联系人和发送短信。这都需要在此文件中定义、声明、注册
 <?xml version="1.0" encoding="utf-8"?>
 <manifest 
 xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.yarin.android.MyContacts"
 android:versionCode="1"
 android:versionName="1.0">
 <application 
 android:icon="@drawable/icon" 
 android:label="@string/app_name">
 <provider 
 android:name="ContactsProvider"
 android:authorities="com.yarin.android.provider.ContactsProvider"/>
 <activity 
 android:name=".MyContacts"
 android:label="@string/app_name">
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
 </activity>
 <activity 
 android:name=".ContactEditor"
 android:label="@string/editor_user">
 <intent-filter>
 <action android:name="android.intent.action.EDIT" />
 <category android:name="android.intent.category.DEFAULT" />
 <data android:mimeType="vnd.android.cursor.item/vnd.yarin.android.mycontacts" />
 </intent-filter>
 <intent-filter>
 <action android:name="android.intent.action.INSERT" />
 <category android:name="android.intent.category.DEFAULT" />
 <data android:mimeType="vnd.android.cursor.dir/vnd.yarin.android.mycontacts" />
 </intent-filter>
 </activity>
 <activity 
 android:name=".ContactView"
 android:label="@string/view_user">
 <intent-filter>
 <action android:name="android.intent.action.VIEW" />
 <category android:name="android.intent.category.DEFAULT" />
 <data android:mimeType="vnd.android.cursor.item/vnd.yarin.android.mycontacts" />
 </intent-filter>
 <intent-filter>
 <category android:name="android.intent.category.DEFAULT" />
 <data android:mimeType="vnd.android.cursor.dir/vnd.yarin.android.mycontacts" />
 </intent-filter>
 </activity>
 </application>
 <uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>
 <uses-permission android:name="android.permission.SEND_SMS"></uses-permission>
 <uses-permission android:name="android.permission.RECEIVE_SMS" />
 <uses-sdk android:minSdkVersion="5" />
 </manifest>