Android切近实战(八)

简介:

美包包,不说了,进入正题。今天老夫要讲的是读取联系人,其实我做这个的初衷是想做一个短信拦截,电话拦截的功能。

我们先看一下界面,还是不错的,挺绚丽的。

wKioL1RbeTHAM8hyAAIo4XZJDwQ669.jpg

OK,我们一看就知道,这又是一个ListView。目前的功能是当你在复选框打钩,点击后面的拨号就会将电话打出去。如果不打钩,电话则不会拨出去。OK,我们先看看页面布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<? xml  version = "1.0"  encoding = "utf-8" ?>
< LinearLayout  xmlns:android = "http://schemas.android.com/apk/res/android"
     android:layout_width = "match_parent"  android:layout_height = "match_parent"
     android:orientation = "vertical" >
     < ListView  android:id = "@+id/contactListView" 
         android:descendantFocusability = "blocksDescendants"
         android:layout_width = "fill_parent"
         android:layout_height = "fill_parent"
         android:divider = "@color/teal"
         android:dividerHeight = "1dp" >
     </ ListView >
     < LinearLayout 
         android:orientation = "horizontal"
         android:layout_width = "fill_parent"
         android:layout_height = "wrap_content" >
         < Button  android:id = "@+id/btnSelAll"
             android:text = "@string/btnSelAll"
             android:textColor = "@color/teal"
             android:textSize = "14dp"
             android:textStyle = "bold"
             android:layout_weight = "1"
             android:layout_width = "fill_parent"
             android:layout_height = "fill_parent" ></ Button >
         < Button  android:id = "@+id/btnInverseSel"
             android:text = "@string/btnSelInverse"
             android:textColor = "@color/teal"
             android:layout_marginLeft = "1dp"
             android:layout_weight = "1"
             android:textSize = "14dp"
             android:textStyle = "bold"
             android:layout_width = "fill_parent"
             android:layout_height = "fill_parent" ></ Button >
         < Button  android:id = "@+id/btnSet"
             android:text = "@string/btnSet"
             android:layout_weight = "1"
             android:textColor = "@color/teal"
             android:layout_marginLeft = "1dp"
             android:textSize = "14dp"
             android:textStyle = "bold"
             android:layout_width = "fill_parent"
             android:layout_height = "fill_parent" ></ Button >
     </ LinearLayout >
</ LinearLayout >

我们再看看ListView要加载的模版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<? xml  version = "1.0"  encoding = "utf-8" ?>
< LinearLayout  xmlns:android = "http://schemas.android.com/apk/res/android"
     android:layout_width = "fill_parent"  android:layout_height = "wrap_content"
     android:id = "@+id/contactTemplate" >
     < TableLayout  android:id = "@+id/tabContatMain"
         android:layout_width = "fill_parent"  android:layout_height = "wrap_content"
         android:stretchColumns = "2"  android:shrinkColumns = "2"  android:padding = "3dip" >
         < TableRow >
             < CheckBox  android:id = "@+id/chkContactUser" 
                 android:layout_gravity = "center_vertical" ></ CheckBox >
             < ImageView  android:id = "@+id/imgContactPhoto"
                 android:layout_gravity = "center_vertical" 
                 android:scaleType = "fitCenter" ></ ImageView >
             < TextView  android:id = "@+id/txtContactName"
                 android:layout_marginLeft = "10dp" 
                 android:layout_gravity = "center_vertical"
                 android:textColor = "@color/teal1" ></ TextView >
             < TextView  android:id = "@+id/txtContactTelNumber"
                 android:layout_marginLeft = "4dp" 
                 android:gravity = "right"
                 android:layout_gravity = "center_vertical" 
                 android:textColor = "@color/yellow" ></ TextView >
             < Button  android:id = "@+id/btnDail" 
                 android:text = "@string/btnDail"
                 android:textSize = "10dp"
                 android:layout_marginLeft = "10dp" 
                 android:width = "60dp"
                 android:drawableRight = "@drawable/dail"
                 android:layout_gravity = "center_vertical" 
                 android:textColor = "@color/purplered" ></ Button >
         </ TableRow >
     </ TableLayout >
</ LinearLayout >

依然是TableLayout布局,我们设置它的收缩列为第二列,伸展列也是第二列。这样如果第二列不够显示则会收缩。OK,我们看一下后台代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.punchinalarm);
         
         owner =  this ;
         btnSelAll = (Button)  this .findViewById(R.id.btnSelAll);
         btnSelInverse = (Button)  this .findViewById(R.id.btnInverseSel);
         btnSet = (Button)  this .findViewById(R.id.btnSet);
         contactUserListView = (ListView)  this
                 .findViewById(R.id.contactListView);
         
         dataList =  new  ArrayList<Map<String, Object>>();
         this .InitData();
     }

在OnCreate方法中,我们初始化数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
private  void  InitData() {
         String phoneUserName =  null ;
         String phoneNumber =  null ;
         Long contactId =  null ;
         Long photoId =  null ;
         Map<String, Object> dataMap =  null ;
 
         ContentResolver resolver =  this .getApplicationContext()
                 .getContentResolver();
 
         /*
          * 获取Sim卡联系人 Uri uri = Uri.parse("content://icc/adn");
          */
         Cursor phoneCursor = resolver.query(Phone.CONTENT_URI,
                 PHONE_PROJECTION,  null null null );
 
         if  (phoneCursor !=  null ) {
             while  (phoneCursor.moveToNext()) {
                 dataMap =  new  HashMap<String, Object>();
                 phoneUserName = phoneCursor.getString( 0 );
                 phoneNumber = phoneCursor.getString( 1 );
                 photoId = phoneCursor.getLong( 2 );
                 contactId = phoneCursor.getLong( 3 );
 
                 if  (phoneNumber ==  null  || phoneNumber.trim().length() <  11 ) {
                     continue ;
                 }
 
                 Bitmap contactPhoto =  null ;
                 if  (photoId >  0 ) {
                     Uri uri = ContentUris.withAppendedId(
                             ContactsContract.Contacts.CONTENT_URI, contactId);
                     InputStream input = ContactsContract.Contacts
                             .openContactPhotoInputStream(resolver, uri);
                     contactPhoto = BitmapFactory.decodeStream(input);
                 else  {
                     contactPhoto = BitmapFactory.decodeResource(getResources(),
                             R.drawable.usersmall);
                 }
 
                 dataMap.put( "UserName" , phoneUserName);
                 dataMap.put( "UserPhoneNumber" , phoneNumber);
                 dataMap.put( "UserPhoto" , contactPhoto);
                 dataList.add(dataMap);
             }
 
             if  (dataList !=  null  && dataList.size() >  0 ) {
                 customAdapter simpleAdapter =  new  customAdapter( this , dataList,
                         R.layout.contactdetailtemplate,  new  String[] {
                                 "UserPhoto" "UserName" "UserPhoneNumber"  },
                         new  int [] { R.id.chkContactUser, R.id.imgContactPhoto,
                                 R.id.txtContactName, R.id.txtContactTelNumber,
                                 R.id.btnDail });
 
                 this .contactUserListView.setAdapter(simpleAdapter);
             }
         }
     }

我们知道外界的程序通过ContentResolver接口可以访问ContentProvider提供的数据,在Activity当中通过getContentResolver()可以得到当前应用的 ContentResolver实例。因为通讯录和短消息都可以通过接口访问,所以我们就可以通过getContentResolver访问SIM卡和手机中的联系人信息。

我们主要到下面的这句

1
2
Cursor phoneCursor = resolver.query(Phone.CONTENT_URI,
                 PHONE_PROJECTION,  null null null );

通过接口查询,我们会得到一个Cursor。通过查看Cursor的定义,我们发现它是个抽象类

1
public  abstract  interface  android.database.Cursor

我们发现它提供了一些方法,如下

wKioL1RbgASRasFnAAEq2WtayDw502.jpg

由此可见,它是一个既可以前进又可以后退的无向游标,类似于SqlServer中的游标。这样的话我们不论是读取联系人信息,还是读取短消息,都可以随时定位游标。

在上面我们看到Query的几个参数,Phone.Content_URI,获取联系人的时候需要去这个URI去取数据。其实这里的Phone.Content_URI的值是content://com.android.contacts/contacts。它的定义如下

 public static final android.net.Uri CONTENT_URI;


ok,我们拿到联系人之后,我们进行循环,游标下移,拿出所有的有电话号码的联系人的数据。因为我们传入的PHONE_PROJECTION的顺序是姓名,电话号码,照片ID,以及一个ContactID。所以我们看到取数据的顺序如下

1
2
3
4
phoneUserName = phoneCursor.getString( 0 );
                 phoneNumber = phoneCursor.getString( 1 );
                 photoId = phoneCursor.getLong( 2 );
                 contactId = phoneCursor.getLong( 3 );

拿到PhotoID之后,我们判断是否大于0,如果大于0,我们会获取用户图像。

获取用户图像的时候,先通过下面的代码将URI和参数连接起来

1
2
ContentUris.withAppendedId(
                             ContactsContract.Contacts.CONTENT_URI, contactId)

其实这个类似于Get方式的API,比如ContactUser/100,意思是获取编号为100的人的信息。

OK,URI构造好之后,我们获取图像

1
2
3
InputStream input = ContactsContract.Contacts
                             .openContactPhotoInputStream(resolver, uri);
                     contactPhoto = BitmapFactory.decodeStream(input);

最后加入List<Map<String,Object>>,对ListView运用适配器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
class  customAdapter  extends  BaseAdapter {
         private  List<Map<String, Object>> dataList;
         private  LayoutInflater mInflater;
         private  Context context;
         private  String[] keyString;
         private  int [] valueViewID;
         Holder holder;
 
         public  customAdapter(Context context,
                 List<Map<String, Object>> dataList,  int  resource,
                 String[] from,  int [] to) {
             this .dataList = dataList;
             this .context = context;