首页 > 网名大全 正文
(qq名字能找到人)通过名字和照片能找到人吗…

时间:2023-03-07 15:26:00 阅读: 评论: 作者:佚名

因为要制作通知、提醒类的应用程序,所以首先想尝试的是支持自己手机通讯录的生日通知。

这里说的android联系人,指的是存储在安卓手机google账户下面的联系人,而不是存储在本机或者某个国产手机系统的联系人。

android联系人

概况

联系人的数据大致分为16类,分别是

  • 电子邮件(地址、电子邮件类型(家庭、工作、手机、其他))。
  • 即时消息(协议(qq、icq、skype 等)、im id)。
  • 昵称。
  • 组织(公司、部门、职务、职位描述、办公地点)。
  • 电话(号码、电话类型(家庭、手机、工作、其他))。
  • sip地址
  • 姓名(显示名称、名字、姓氏)。
  • 邮政地址(国家、城市、地区、街道、邮政编码)。
  • 身份(命名空间(SSN、护照)、号码)。
  • 照片。
  • 组(联系人属于组 id)。
  • 网站(网站 url,网站类型())。
  • 笔记。
  • 事件(生日、其它自定义事件)
  • 关系
  • msic 对于某些组,例如电子邮件、电话、地址等。信息还根据数据使用情况进行分类,例如在家中使用、在工作中使用等。

存储地址

所有 android 联系信息都保存在 SQLite 数据库中。 数据库文件位于 /data/data。 我们可以使用 android模拟器上查看上述数据库文件。 如果无法打开上述文件夹,请在 dos 或 shell 窗口中运行 adb root shell 命令。

adb devices adb shell su sqlite3 /data/data select * from sqlite_master where type="table"; // 我们可以先查看这个数据库里面有哪些表,太多了 select * from sqlite_master where type="table" and name = "data"; // 查看data表的结构

我们可以看到当时这个表是这么创建的

CREATE TABLE data ( _id INTEGER PRIMARY KEY AUTOINCREMENT, package_id INTEGER REFERENCES package(_id), mimetype_id INTEGER REFERENCES mimetype(_id) NOT NULL, raw_contact_id INTEGER REFERENCES raw_contacts(_id) NOT NULL, hash_id TEXT, is_read_only INTEGER NOT NULL DEFAULT 0, is_primary INTEGER NOT NULL DEFAULT 0, is_super_primary INTEGER NOT NULL DEFAULT 0, data_version INTEGER NOT NULL DEFAULT 0, data1 TEXT,data2 TEXT,data3 TEXT,data4 TEXT,data5 TEXT,data6 TEXT,data7 TEXT,data8 TEXT,data9 TEXT,data10 TEXT,data11 TEXT,data12 TEXT,data13 TEXT,data14 TEXT,data15 TEXT, data_sync1 TEXT, data_sync2 TEXT, data_sync3 TEXT, data_sync4 TEXT, carrier_presence INTEGER NOT NULL DEFAULT 0, preferred_phone_account_component_name TEXT, preferred_phone_account_id TEXT )

其中有data1 ~ data15,data_sync1 ~ data_sync4

其实对于我们常用的就是mimetype_id、raw_contact_id 、data1 、data2、data3,数据的类型就是mimetype_id,数据的内容就是data1,而data2、data3则是用来辅助data1,如果mimetype_id对应的是电话号码这组数据,data1就是电话号码,而data2就是电话类型(比如手机,座机)、data3就是自定义的电话类型(比如data2中的分类都不满足,你自定义的紧急电话类型) 数据库中的几个我们能用的表都是依靠相同的raw_contact_id 连接起来的。

select * from sqlite_master where type="table" and name = "mimetypes"; // 查看data表的结构

该表是这么创建的

CREATE TABLE mimetypes ( _id INTEGER PRIMARY KEY AUTOINCREMENT, mimetype TEXT NOT NULL )

举个例子

select _id, raw_contact_id,mimetype_id, data1, data2, data3 from data order by _id desc limit 20;

红框中的1267就是一个raw_contact_id ,可以看到这里的6条记录都是我们Test这个联系人的数据: 第一行mimetype_id为5,可以看出是手机号码 第四行mimetype_id为7,可以看出是名字 第六行mimetype_id为13,可以看出是事件,这里存档是日期,根据后面的data2为3可以区分出是生日。 其它的几个是空的,对应的可以根据上面的mimetypes找到对应的含义。

实战

知道了数据的存储结构了,我们就可以开始查询了

我们可用一个fragment来展示联系人列表数据,fragment同时继承接口LoaderManager.LoaderCallbacks<cursor>

lateinit var contactsList: ListView // Defines a variable for the search string private val searchString: String = "" private var lookupKey: String = "" // An adapter that binds the result cursor to the ListView private var cursorAdapter: SimpleCursorAdapter? = null private val detailSelectionArgs = arrayOf<String>("") private val selectionArgs = arrayOf<String>(searchString) // 联系人姓名兼容老版本 private val DISPLAY_NAME: String = if >= Build.VERSION_CODES.HONEYCOMB)) { Con } else { Con } // 类似于mysql select 对应的数据列 private val PROJECTION: Array<out String> = arrayOf( Con, Con, DISPLAY_NAME, Con ) // 类似于mysql的where语句 private val SELECTION: String = if >= Build.VERSION_CODES.HONEYCOMB) "${Con} LIKE ?" else "${Con} LIKE ?" // cursor数据对应列 private val FROM_COLUMNS: Array<String> = arrayOf( DISPLAY_NAME, Con, Con ) // cursor数据对应列对应的展示位置ID private val TO_IDS: IntArray = intArrayO, R.id.msgTitle, R.id.msgBody) private var DETAIL_SELECTION: String = Con + " = ? AND " + Con + " IN ('" + Con + "', '" + Con + "', '" + Con + "', '" + Con + "')" private val DETAIL_PROJECTION: Array<out String> = arrayOf( Con, Con, Con, Con, Con, Con, )override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = Fragmen(inflater, container, false) val root: View = binding.root contactsList = root.findViewById) textView = root.findViewById_text) textView?.text = "loading..." self = this // initDataFromMock(); activity?.also { // Gets a CursorAdapter cursorAdapter = SimpleCursorAdapter( it, R.layout.msg_item, // ListView对应的layout xml文件 null, FROM_COLUMNS, TO_IDS, 0 ) // Sets the adapter for the ListView con = cursorAdapter } // Initializes the loader LoaderManager.getInstance(this).initLoader(2, null, this) return root }override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { /* * Makes search string into pattern and * stores it in the selection array */ loaderFlag = id selectionArgs[0] = "%$searchString%" val mLoader = activity?.let { CursorLoader( it, Con, PROJECTION, SELECTION, selectionArgs, SORT_ORDER ) } // Starts the query return mLoader ?: throw IllegalStateException() } } override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor?) { // Put the result Cursor in the adapter for the ListView cursorAdapter?.swapCursor(cursor) // 用进程打印列表数据 Thread { val userList: ArrayList<User> = arrayListOf(); // 因为列表的查询没有指定搜索条件(searchString为空),查询的是全部数据,那样每个联系会出来好几条数据,可以简单用个hashMap去重下 var userHashMap: HashMap<String, User> = HashMap(); try { while ()) { val contactId = cur(0) val contactKey = cur(1) val contactName = cur(2) var currentInfos: MutableList<String?> = ArrayList() curren("contactName = $contactName") var userPhoneList : ArrayList<UserPhone> = arrayListOf(); var userEventList : ArrayList<UserEvent> = arrayListOf(); // 我们可以用类似的方式查询该联系对应的具体数据 val cr: ContentResolver = requireActivity().contentResolver detailSelectionArgs[0] = contactKey!! val curs: Cursor? = cr.query(Con, DETAIL_PROJECTION, DETAIL_SELECTION, detailSelectionArgs, null) if (curs != null) { while ()) { val id: Long = cur(0) val name: String = curs.getString(1) // full name val mime: String = curs.getString(2) // type of data (phone / birthday / email) val data: String? = curs.getString(3) // the actual info, e.g. +1-212-555-1234 var type: String? = curs.getString(4); var label: String? = curs.getString(5); var kind = "unknown" when (mime) { Con -> { kind = "phone" u(UserPhone(contactKey, data, type, label)) } Con -> { kind = "event" u(UserEvent(contactKey, data, type, label)) } Con -> kind = "email" Con -> kind = "note" } if (data != null) { currentInfos!!.add("$kind = $data/$type/$label") } } Log.i("CURRENT", contactName + "_" + contactId + "_" + curren()) } val user = User(contactKey, contactId, contactName, userPhoneList, userEventList, null); if (!u) && u > 0) { u, user); u(User(contactKey, contactId, contactName, userPhoneList, userEventList, null)) } } } catch (e: Exception) { Log.e("ABC", "while error $e") } Log.i("EFG", u()) if > 0) { val userListStr = Gson().toJson(userList); U(requireContext(), "test", "userList", userListStr) // textView?.text = "list: " + u() Log.i("LIST", u()) } }.start() }

代码有所截取,可能有部分变量什么的遗漏的,但是示意是足够了。

本文启发自 Android Contacts Database Structure Retrieve a list of contacts

  • 相关阅读
  • 评论列表

发表评论: