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;
             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,最后我们希望在按回退键的时候,弹出是否退出的提示

wKiom1RbjdHDxnOlAAGKTIuOxw4762.jpg

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测试机。

wKiom1Rbj22DJ0SbAAHqhJl9btY782.jpgwKiom1Rbj6DRdUVHAATC_rI71sI887.jpg



本文转自 BruceAndLee 51CTO博客,原文链接:http://blog.51cto.com/leelei/1573863,如需转载请自行联系原作者


相关文章
|
7天前
Android4.1.0实战教程---自动阅读小说
Android4.1.0实战教程---自动阅读小说
46 0
|
5天前
|
前端开发 Android开发
Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)
Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)
Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)
|
5天前
|
Android开发
Android高级开发面试题以及笞案整理,实战解析
Android高级开发面试题以及笞案整理,实战解析
|
5天前
|
Android开发
Android Jetpack架构开发组件化应用实战,字节跳动+阿里+华为+腾讯等大厂Android面试题
Android Jetpack架构开发组件化应用实战,字节跳动+阿里+华为+腾讯等大厂Android面试题
|
5天前
|
Android开发
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
|
6天前
|
设计模式 Android开发 Java
实战案例,精选Android面试真题集锦
实战案例,精选Android面试真题集锦
|
7天前
|
缓存 Java Android开发
Android应用性能优化实战
【5月更文挑战第14天】 在竞争激烈的应用市场中,一个流畅、高效的应用能显著提升用户体验并增强用户黏性。本文深入探讨了针对安卓平台进行应用性能优化的策略与实践,从内存管理到多线程处理,再到布局渲染和网络请求的优化,旨在为开发者提供一套全面的优化工具箱。通过分析常见的性能瓶颈并结合最新的Android技术动态,我们不仅讨论理论,还将分享具体的代码示例和改进方法,帮助开发者在实际应用中实现性能提升。
|
7天前
|
编解码 缓存 监控
安卓应用性能优化实战
【5月更文挑战第14天】 在当今移动应用竞争激烈的市场中,一款应用的性能直接影响用户体验和留存率。特别是对于安卓平台,由于设备多样性和应用生态环境的复杂性,性能优化显得尤为重要。本文将深入探讨安卓应用的性能瓶颈,分析影响性能的关键因素,并通过具体的代码实践和工具使用,展示如何有效提升安卓应用的响应速度和流畅度。内容覆盖从UI渲染优化、内存管理到电池使用效率的多个方面,旨在为开发者提供一套实用的性能优化策略。
|
7天前
|
移动开发 API Android开发
Android应用性能优化实战
【4月更文挑战第28天】在移动开发领域,一个流畅的用户体验是至关重要的。对于Android开发者而言,应用的性能优化是一项既挑战性也极其重要的工作。本文将深入探讨Android应用性能优化的多个方面,包括内存管理、UI渲染、多线程处理以及电池效率等,旨在为开发者提供实用的性能提升策略和具体的实施步骤。通过分析常见的性能瓶颈,并结合最新的Android系统特性和工具,我们的目标是帮助读者打造更加高效、响应迅速的Android应用。
|
7天前
|
缓存 监控 Android开发
Android 应用性能优化实战
【4月更文挑战第27天】 在竞争激烈的移动应用市场中,性能优越的应用更能吸引和保留用户。针对Android平台,本文将深入探讨影响应用性能的关键因素,并提供一系列实用的优化策略。我们将从内存管理、UI渲染、多线程处理以及电池使用效率等方面入手,通过具体案例分析如何诊断常见问题,并给出相应的解决方案。文中所提技巧旨在帮助开发者构建更加流畅、高效的Android应用。
24 2