一:增加一个展现数据的布局
<?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/contactsView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
二:增加 BaseActivity
abstract class BaseActivity : AppCompatActivity() {
/**
* kotlin 容许一个类继承另一个类
* kotlin 所有的类都继承自 Any 类(Any 不是 java.lang.Object)* Any 类是所有类的超类,对于没有超类型申明的类是默认超类
* Kotlin 规定一个类能够给继承,必须应用 open 关键字润饰
* */
/**
* 抽象类:关键字为 abstract
* 形象函数:abstract fun initView()
* 形象属性:abstract var name:String */
/**
* 变量能够定义为可变 (var) 和不可变(val)* 常量定义:val 相当于被 final 润饰 var 相当于可变非 final 润饰
* 等价于 Java:public static final String TAG=BaseActivity.class.getSimpleName()*/
// 定义标记
open val TAG: String = this.javaClass.simpleName
// 初始化布局 View
abstract fun initView()
// 初始化数据
abstract fun initData()
// 初始化获取布局 id, 带返回值的形象办法
abstract fun getLayoutId(): Int
/**
* 语法定义
* fun 办法名(参数名:参数类型):返回值类型{
*
* return 返回值
*
* }
*
* 无返回值能够应用 Unit 代替返回值类型 ? 代表可空
* Kotlin 是 null 平安的语言 Byte ,Short,Int ,Long 型的变量都是不能承受 null 值,如果要存储 null 值须要应用 Byte?,Short?,Int?,Long?
*
* override fun onCreate(savedInstanceState: Bundle?):Unit{
*
* }
**/
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
setContentView(getLayoutId())
initView()
initData()}
override fun onDestroy() {super.onDestroy()
}
}
三:定义 FourActivity, 实现权限受权和联系人数据 ContentResolver 解析过程间通信
class FourActivity : BaseActivity() {
private val CONTACT_REQUEST_CODE = 1
//ListView 布局文件
lateinit var contactsView: ListView
// 汇合数据
private val contactsList = ArrayList<String>()
// 适配器
private lateinit var adapter: ArrayAdapter<String>
override fun initView() {contactsView = findViewById<ListView>(R.id.contactsView)
adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, contactsList)
contactsView.adapter = adapter
// 权限查看
checkP(this)
}
private fun checkP(context: Context) {
// 查看权限是否受权,这个查看的权限是读取手机联系人
if (ContextCompat.checkSelfPermission(
context,
android.Manifest.permission.READ_CONTACTS
) != PackageManager.PERMISSION_GRANTED
) {
// 没有受权,申请权限受权
// 参数类型,Activity, 权限组,申请码
ActivityCompat.requestPermissions(
context as Activity,
arrayOf(android.Manifest.permission.READ_CONTACTS),
CONTACT_REQUEST_CODE
)
} else {
// 受权了
readContacts()}
}
/** 权限申请点击容许和回绝都会回调 onRequestPermissionsResult 办法 */
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
CONTACT_REQUEST_CODE -> {if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 容许受权
readContacts()} else {
// 回绝受权
Toast.makeText(this, "You denied the Permission", Toast.LENGTH_SHORT).show()}
}
}
}
/** 读取联系人操作,应用 ContentProvider*/
private fun readContacts() {
// 查问联系人数据
contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
null,
null,
null
)?.apply {while (moveToNext()) {
// 获取联系人姓名
val displayName =
getString(getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
// 获取联系人手机号
val number =
getString(getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
contactsList.add("$displayName\n$number")
adapter.notifyDataSetChanged()
/**
* 剖析 log:android.database.StaleDataException: Attempted to access a cursor after it has been
* 然而同样的代码在 android2.2 上边没有产生,在 android3.0 上边产生了,剖析起因在于
android4.0 的 managedCursor /managedQuery 会主动的 close 一个 cursor,然而咱们又手动的敞开了一次,所以导致了这个问题,解决方案是在 4.0 的代码去掉 close 这个操作。*/
if (Integer.parseInt(Build.VERSION.SDK) < 11) {close()
}
}
}
}
override fun initData() {}
override fun getLayoutId(): Int {return R.layout.activity_four}
}
四:增加权限在 AndroidManifest
<uses-permission android:name="android.permission.READ_CONTACTS"/>