美包包,不说了,进入正题。今天老夫要讲的是读取联系人,其实我做这个的初衷是想做一个短信拦截,电话拦截的功能。
我们先看一下界面,还是不错的,挺绚丽的。
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
|
我们发现它提供了一些方法,如下
由此可见,它是一个既可以前进又可以后退的无向游标,类似于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;
mInflater = (LayoutInflater)
this
.context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
keyString =
new
String[from.length];
valueViewID =
new
int
[to.length];
System.arraycopy(from,
0
, keyString,
0
, from.length);
System.arraycopy(to,
0
, valueViewID,
0
, to.length);
}
@Override
public
int
getCount() {
return
dataList.size();
}
@Override
public
Object getItem(
int
position) {
return
dataList.get(position);
}
@Override
public
long
getItemId(
int
position) {
return
position;
}
public
void
removeItem(
int
position) {
dataList.remove(position);
this
.notifyDataSetChanged();
}
public
View getView(
int
position, View convertView, ViewGroup parent) {
if
(convertView !=
null
) {
holder = (Holder) convertView.getTag();
}
else
{
convertView = mInflater.inflate(R.layout.contactdetailtemplate,
null
);
holder =
new
Holder();
holder.chkContactUser = (CheckBox) convertView
.findViewById(valueViewID[
0
]);
holder.imgUserPhoto = (ImageView) convertView
.findViewById(valueViewID[
1
]);
holder.labUserName = (TextView) convertView
.findViewById(valueViewID[
2
]);
holder.labPhoneNumber = (TextView) convertView
.findViewById(valueViewID[
3
]);
holder.btnDail = (Button) convertView
.findViewById(valueViewID[
4
]);
convertView.setTag(holder);
}
Map<String, Object> appInfo = dataList.get(position);
if
(appInfo !=
null
) {
String userName = appInfo.get(keyString[
1
]).toString();
String userPhoneNumber = appInfo.get(keyString[
2
]) ==
null
?
""
: appInfo.get(keyString[
2
]).toString();
Bitmap userPhoto = (Bitmap) appInfo.get(keyString[
0
]);
holder.labUserName.setText(userName);
holder.labPhoneNumber.setText(userPhoneNumber);
holder.imgUserPhoto.setImageBitmap(userPhoto);
holder.btnDail.setOnClickListener(
new
ViewButtonListener(
position, holder.chkContactUser));
}
return
convertView;
}
}
class
Holder {
public
TextView labUserName;
public
TextView labPhoneNumber;
public
ImageView imgUserPhoto;
public
Button btnDail;
public
CheckBox chkContactUser;
}
|
这里,其实很简单,我们就是拿到控件,然后根据Position,拿到List中的某行数据,然后赋值。
最后我们看看按钮的Click事件,我们传入了Position和每行的CheckBox。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class
ViewButtonListener
implements
OnClickListener {
private
int
position;
Object phoneNumber;
CheckBox chkContactUser;
ViewButtonListener(
int
position,CheckBox chkContactUser) {
this
.position = position;
this
.phoneNumber = dataList.get(position).get(
"UserPhoneNumber"
);
this
.chkContactUser= chkContactUser;
}
@Override
public
void
onClick(View view) {
int
vid = view.getId();
if
(vid == R.id.btnDail&&chkContactUser.isChecked()) {
Intent dialIntent =
new
Intent(Intent.ACTION_CALL, Uri
.parse(
"tel:"
+ phoneNumber));
startActivity(dialIntent);
}
}
}
|
在OnClick中,我们判断如果是拨号按钮并且列头的CheckBox是勾选的,则会拨号,否则不会拨号。OK,最后我们希望在按回退键的时候,弹出是否退出的提示
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
|
public
boolean
onKeyDown(
int
keyCode, KeyEvent event) {
if
((keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() ==
0
)) {
dialog();
return
true
;
}
return
true
;
}
protected
void
dialog() {
AlertDialog.Builder builder =
new
Builder(punchinalarm.
this
);
builder.setMessage(
"确定要退出吗?"
);
builder.setTitle(
"提示"
);
builder.setPositiveButton(
"确认"
,
new
DialogInterface.OnClickListener() {
@Override
public
void
onClick(DialogInterface dialog,
int
which) {
dialog.dismiss();
android.os.Process.killProcess(android.os.Process.myPid());
}
});
builder.setNegativeButton(
"取消"
,
new
android.content.DialogInterface.OnClickListener() {
@Override
public
void
onClick(DialogInterface dialog,
int
which) {
dialog.dismiss();
}
});
builder.create().show();
}
|
最后,哥们的博客是货真价实,小米3测试机。
本文转自 BruceAndLee 51CTO博客,原文链接:http://blog.51cto.com/leelei/1573863,如需转载请自行联系原作者