Android联系人模块分析(三)

Android contacts 联系人 通讯录 源码 完全解析 Android contacts 联系人 通讯录 源码 完全解析Android contacts 联系人 通讯录 源码 完全解析 1简介 2软件架构 3各功能模块分析 1联系人数据的显示 1联系人列表显示 2联系人详细信息数据的显示 2联系人数据的编辑和存储 1编辑界面相关 2数据存储相关 3Sim联系人数据的整合 1Sim卡联系人数据的显示 2开机自动导入Sim卡联系人 3telephony中Ic 阅读详情



       前两篇文章主要讲解了ContactsProvider的结构,这篇文章想详细分析一下ContactsProvider的底层数据表结构(Android4.1.1),和大家一起深入的理解其内部实现。

       ContactsProvider的代码路径位于packages/providers/ContactsProvider/src下,我们可以结合实际的场景来分析ContactsProvider的代码逻辑。

       首先从ContactsPovider的数据库开始分析,数据是ContactsProvider的基础。如前所述,ContactsDatabaseHelper类创建了联系人数据库,数据库中包括表、视图、触发器,并且为部分表项创建了索引。

  一、数据库的定义:

static final int DATABASE_VERSION = 704;
private static final String DATABASE_NAME = "contacts2.db";
private static final String DATABASE_PRESENCE = "presence_db";

         DATABASE_VERSION定义了该数据库的版本号,版本号可以用来判断该数据库是否需要升级,即是否执行onUpgrade方法。

         DATABASE_NAME定义了该数据库的名称,也是序列化到磁盘上的文件名称。

         DATABASE_PRESENCE是内存数据库的名称,在contacts db中,创建了一份内存数据库,用来存储联系人的实时状态信息,这部分数据需要快速、频繁的操作,且无需序列化,所以采用了内存数据库的方式,创建的代码如下:

db.execSQL("ATTACH DATABASE ':memory:' AS " + DATABASE_PRESENCE + ";");

         内存数据库的创建过程定义在onOpen方法中,由于目前没有涉及到StatusUpdates的内容,所以暂时不详细分析这部分内容,但是从这部分内容我们也可以看到,Google还是有想法要把通讯录做成社交化的通讯录,现在已经预留了这些和IM的接口。

 二、表结构的定义:

public interface Tables {
        public static final String CONTACTS = "contacts";
        public static final String RAW_CONTACTS = "raw_contacts";
        public static final String STREAM_ITEMS = "stream_items";
        public static final String STREAM_ITEM_PHOTOS = "stream_item_photos";
        public static final String PHOTO_FILES = "photo_files";
        public static final String PACKAGES = "packages";
        public static final String MIMETYPES = "mimetypes";
        public static final String PHONE_LOOKUP = "phone_lookup";
        public static final String NAME_LOOKUP = "name_lookup";
        public static final String AGGREGATION_EXCEPTIONS = "agg_exceptions";
        public static final String SETTINGS = "settings";
        public static final String DATA = "data";
         上述代码只是表名称定义的一部分,读者可以挑选几个自己感兴趣的数据表,分析一下其创建过程,比如raw contact表的创建代码如下:

        // Raw_contacts table
        db.execSQL("CREATE TABLE " + Tables.RAW_CONTACTS + " (" +
                RawContacts._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                RawContactsColumns.ACCOUNT_ID + " INTEGER REFERENCES " +
                    Tables.ACCOUNTS + "(" + AccountsColumns._ID + ")," +
                RawContacts.SOURCE_ID + " TEXT," +
                RawContacts.RAW_CONTACT_IS_READ_ONLY + " INTEGER NOT NULL DEFAULT 0," +
                RawContacts.VERSION + " INTEGER NOT NULL DEFAULT 1," +
                RawContacts.DIRTY + " INTEGER NOT NULL DEFAULT 0," +
                RawContacts.DELETED + " INTEGER NOT NULL DEFAULT 0," +
                RawContacts.CONTACT_ID + " INTEGER REFERENCES contacts(_id)," +
                RawContacts.AGGREGATION_MODE + " INTEGER NOT NULL DEFAULT " +
                        RawContacts.AGGREGATION_MODE_DEFAULT + "," +
                RawContactsColumns.AGGREGATION_NEEDED + " INTEGER NOT NULL DEFAULT 1," +
                RawContacts.CUSTOM_RINGTONE + " TEXT," +
                RawContacts.SEND_TO_VOICEMAIL + " INTEGER NOT NULL DEFAULT 0," +
                RawContacts.TIMES_CONTACTED + " INTEGER NOT NULL DEFAULT 0," +
                RawContacts.LAST_TIME_CONTACTED + " INTEGER," +
                RawContacts.STARRED + " INTEGER NOT NULL DEFAULT 0," +
                RawContacts.DISPLAY_NAME_PRIMARY + " TEXT," +
                RawContacts.DISPLAY_NAME_ALTERNATIVE + " TEXT," +
                RawContacts.DISPLAY_NAME_SOURCE + " INTEGER NOT NULL DEFAULT " +
                        DisplayNameSources.UNDEFINED + "," +
                RawContacts.PHONETIC_NAME + " TEXT," +
                RawContacts.PHONETIC_NAME_STYLE + " TEXT," +
                RawContacts.SORT_KEY_PRIMARY + " TEXT COLLATE " +
                        ContactsProvider2.PHONEBOOK_COLLATOR_NAME + "," +
                RawContacts.SORT_KEY_ALTERNATIVE + " TEXT COLLATE " +
                        ContactsProvider2.PHONEBOOK_COLLATOR_NAME + "," +
                RawContacts.NAME_VERIFIED + " INTEGER NOT NULL DEFAULT 0," +
                RawContacts.SYNC1 + " TEXT, " +
                RawContacts.SYNC2 + " TEXT, " +
                RawContacts.SYNC3 + " TEXT, " +
                RawContacts.SYNC4 + " TEXT " +
        ");");

        db.execSQL("CREATE INDEX raw_contacts_contact_id_index ON " + Tables.RAW_CONTACTS + " (" +
                RawContacts.CONTACT_ID +
        ");");

        db.execSQL("CREATE INDEX raw_contacts_source_id_account_id_index ON " +
                Tables.RAW_CONTACTS + " (" +
                RawContacts.SOURCE_ID + ", " +
                RawContactsColumns.ACCOUNT_ID +
        ");");
             从上述代码中,可以发现在raw conacts表上还为字段CONTACT_ID和SOURCE_ID+ACCOUNT_ID创建了索引。

 三、 视图的定义;

       为了提高查询速度,ContactsProvider提供了部分视图,以下为视图名称定义的代码(位于ContactsDatabaseHelper.java文件中)

public interface Views {
        public static final String DATA = "view_data";
        public static final String RAW_CONTACTS = "view_raw_contacts";
        public static final String CONTACTS = "view_contacts";
        public static final String ENTITIES = "view_entities";
        public static final String RAW_ENTITIES = "view_raw_entities";
        public static final String GROUPS = "view_groups";
        public static final String DATA_USAGE_STAT = "view_data_usage_stat";
        public static final String STREAM_ITEMS = "view_stream_items";
    }
       下面以view_data视图为例,说明其创建过程,所有的视图创建都封装在成员方法createContactsView中,如下: 
    private void createContactsViews(SQLiteDatabase db) {
        db.execSQL("DROP VIEW IF EXISTS " + Views.CONTACTS + ";");
        db.execSQL("DROP VIEW IF EXISTS " + Views.DATA + ";");
        db.execSQL("DROP VIEW IF EXISTS " + Views.RAW_CONTACTS + ";");
        db.execSQL("DROP VIEW IF EXISTS " + Views.RAW_ENTITIES + ";");
        db.execSQL("DROP VIEW IF EXISTS " + Views.ENTITIES + ";");
        db.execSQL("DROP VIEW IF EXISTS " + Views.DATA_USAGE_STAT + ";");
        db.execSQL("DROP VIEW IF EXISTS " + Views.STREAM_ITEMS + ";");
        而view_data视图的创建代码为:

        String dataSelect = "SELECT "
                + DataColumns.CONCRETE_ID + " AS " + Data._ID + ","
                + Data.RAW_CONTACT_ID + ", "
                + RawContactsColumns.CONCRETE_CONTACT_ID + " AS " + RawContacts.CONTACT_ID + ", "
                + syncColumns + ", "
                + dataColumns + ", "
                + contactOptionColumns + ", "
                + contactNameColumns + ", "
                + baseContactColumns + ", "
                + buildDisplayPhotoUriAlias(RawContactsColumns.CONCRETE_CONTACT_ID,
                        Contacts.PHOTO_URI) + ", "
                + buildThumbnailPhotoUriAlias(RawContactsColumns.CONCRETE_CONTACT_ID,
                        Contacts.PHOTO_THUMBNAIL_URI) + ", "
                + dbForProfile() + " AS " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + ", "
                + Tables.GROUPS + "." + Groups.SOURCE_ID + " AS " + GroupMembership.GROUP_SOURCE_ID
                + " FROM " + Tables.DATA
                + " JOIN " + Tables.MIMETYPES + " ON ("
                +   DataColumns.CONCRETE_MIMETYPE_ID + "=" + MimetypesColumns.CONCRETE_ID + ")"
                + " JOIN " + Tables.RAW_CONTACTS + " ON ("
                +   DataColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID + ")"
                + " JOIN " + Tables.ACCOUNTS + " ON ("
                +   RawContactsColumns.CONCRETE_ACCOUNT_ID + "=" + AccountsColumns.CONCRETE_ID
                    + ")"
                + " JOIN " + Tables.CONTACTS + " ON ("
                +   RawContactsColumns.CONCRETE_CONTACT_ID + "=" + ContactsColumns.CONCRETE_ID + ")"
                + " JOIN " + Tables.RAW_CONTACTS + " AS name_raw_contact ON("
                +   Contacts.NAME_RAW_CONTACT_ID + "=name_raw_contact." + RawContacts._ID + ")"
                + " LEFT OUTER JOIN " + Tables.PACKAGES + " ON ("
                +   DataColumns.CONCRETE_PACKAGE_ID + "=" + PackagesColumns.CONCRETE_ID + ")"
                + " LEFT OUTER JOIN " + Tables.GROUPS + " ON ("
                +   MimetypesColumns.CONCRETE_MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE
                +   "' AND " + GroupsColumns.CONCRETE_ID + "="
                        + Tables.DATA + "." + GroupMembership.GROUP_ROW_ID + ")";

        db.execSQL("CREATE VIEW " + Views.DATA + " AS " + dataSelect);
            读者可以仔细阅读一下创建该试图的SQL语句,这里就不详细分析这条SQL语句。基于这个视图我们就能提供快速查询功能,我们来看一下ContactsProvider提供了URI来查询该视图,在UriMatcher中,增加了通过email来查询的URI:

        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup", EMAILS_LOOKUP);
        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP);
           咱们可以找到对EMAILS_LOOKUP进行查询处理的逻辑,如下:

            case EMAILS_LOOKUP: {
                setTablesAndProjectionMapForData(qb, uri, projection, false);
                qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = "
                        + mDbHelper.get().getMimeTypeIdForEmail());
                if (uri.getPathSegments().size() > 2) {
                    String email = uri.getLastPathSegment();
                    String address = mDbHelper.get().extractAddressFromEmailAddress(email);
                    selectionArgs = insertSelectionArg(selectionArgs, address);
                    qb.appendWhere(" AND UPPER(" + Email.DATA + ")=UPPER(?)");
                }
                // unless told otherwise, we'll return visible before invisible contacts
                if (sortOrder == null) {
                    sortOrder = "(" + RawContacts.CONTACT_ID + " IN " +
                            Tables.DEFAULT_DIRECTORY + ") DESC";
                }
                break;
            }
             setTablesAndProjectionMapForData主要做SQL语句的封装,下面if语句内的内容是用来准备查询条件,首先取出email字符串,然后利用email值来生成selection条件。代码本身并不复杂,有兴趣的读者可以仔细研读。既然ContactsProvider提供了这样的接口,即通过email获得contact id,那么怎么使用呢,下面给出查询示例:

             Uri uri = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(email));
             Cursor c = getContentResolver().query(uri,
             	new String[]{Email.CONTACT_ID, Email.DISPLAY_NAME, Email.DATA},
             	null, null, null);
            以上就是通过Email获得该联系人的信息的方法。
            读者可以自己完成,通过手机号码去的联系人信息的方法。

    四、触发器的定义

触发器的定义在函数createContactsTriggers中,以RAW_CONTACTS表中的触发器为例,看如下代码:

db.execSQL("DROP TRIGGER IF EXISTS " + Tables.RAW_CONTACTS + "_deleted;");
db.execSQL("CREATE TRIGGER " + Tables.RAW_CONTACTS + "_deleted "
                + "   BEFORE DELETE ON " + Tables.RAW_CONTACTS
                + " BEGIN "
                + "   DELETE FROM " + Tables.DATA
                + "     WHERE " + Data.RAW_CONTACT_ID
                                + "=OLD." + RawContacts._ID + ";"
                + "   DELETE FROM " + Tables.AGGREGATION_EXCEPTIONS
                + "     WHERE " + AggregationExceptions.RAW_CONTACT_ID1
                                + "=OLD." + RawContacts._ID
                + "        OR " + AggregationExceptions.RAW_CONTACT_ID2
                                + "=OLD." + RawContacts._ID + ";"
                + "   DELETE FROM " + Tables.VISIBLE_CONTACTS
                + "     WHERE " + Contacts._ID + "=OLD." + RawContacts.CONTACT_ID
                + "       AND (SELECT COUNT(*) FROM " + Tables.RAW_CONTACTS
                + "            WHERE " + RawContacts.CONTACT_ID + "=OLD." + RawContacts.CONTACT_ID
                + "           )=1;"
                + "   DELETE FROM " + Tables.DEFAULT_DIRECTORY
                + "     WHERE " + Contacts._ID + "=OLD." + RawContacts.CONTACT_ID
                + "       AND (SELECT COUNT(*) FROM " + Tables.RAW_CONTACTS
                + "            WHERE " + RawContacts.CONTACT_ID + "=OLD." + RawContacts.CONTACT_ID
                + "           )=1;"
                + "   DELETE FROM " + Tables.CONTACTS
                + "     WHERE " + Contacts._ID + "=OLD." + RawContacts.CONTACT_ID
                + "       AND (SELECT COUNT(*) FROM " + Tables.RAW_CONTACTS
                + "            WHERE " + RawContacts.CONTACT_ID + "=OLD." + RawContacts.CONTACT_ID
                + "           )=1;"
                + " END");
                上述代码,在RAW_CONTACTS表上创建了一个触发器,当从RAW_CONTACTS表里删除记录时,会通过触发器自动删除该RAW_CONTACT_ID对应的DATA表、CONTACTS表等其他表中的信息。再来看一个比较重要的触发器:

db.execSQL("DROP TRIGGER IF EXISTS " + Tables.RAW_CONTACTS + "_marked_deleted;");
db.execSQL("CREATE TRIGGER " + Tables.RAW_CONTACTS + "_marked_deleted "
                + "   AFTER UPDATE ON " + Tables.RAW_CONTACTS
                + " BEGIN "
                + "   UPDATE " + Tables.RAW_CONTACTS
                + "     SET "
                +         RawContacts.VERSION + "=OLD." + RawContacts.VERSION + "+1 "
                + "     WHERE " + RawContacts._ID + "=OLD." + RawContacts._ID
                + "       AND NEW." + RawContacts.DELETED + "!= OLD." + RawContacts.DELETED + ";"
                + " END");
                上述的触发器,在RAW_CONTACTS表发生UPDATE时,会将其VERSION加1,其实出发VERSION加1的逻辑还有其他几个,读者可以自行分析,这里的VERSION字段可以用来做数据比较,还是非常有用的。

           

               数据库的基本操作暂时介绍到这,如果您想深入的理解Android联系人模块,这部分代码还是需要掌握的,掌握了基础设施,才有可能了解上层建筑。



安卓中通过intent组件跳转到系统联系人编辑界面,及具体案例分析 本人对于intent的用法的一些总结,在此抛砖引玉,还望大家多提建议,共勉!!! 阅读详情

相关推荐

安卓逆向分析步骤总结

start:2020年9月3日 一、前言 安卓逆向说好听一点叫逆向分析学习技术,说不好听就叫破解App了。但是,技术这个东西本身不分好坏,只是看你学会它之后用在哪些方面了。这篇博客用于总结我对安卓逆向分析的学习理解,主要以分析的步骤来表现,当然同时也提供给大家学习交流,仅此而已。 我们应当努力奋斗,有所作为。这样,我们就可以说,我们没有虚度年华,并有可能在时间的沙滩上留下我们的足迹。——拿破仑 二、工具准备 主要: Android Killer 用于反编译/回编APK j...

qq_18401643的博客 8304

Android 5.0 Contacts源码分析

最近工作中要整理最新的Android L的联系人源码分析,在网上各种搜索都不怎么满意,要么版本太老,要么分析的太浅层次了,要么只有简单的使用。无奈就自己整理,发出来共享一下。

lsmfeixiang的专栏 6623

Android实现@联系人功能的全面指南

htmltable {th, td {th {pre {简介:本文详细介绍了在Android应用中如何实现“@联系人功能”,类似于微信聊天中的提及功能。这需要理解并实现包括监听文本输入、构建联系人列表、显示联系人选择界面、处理选择结果、显示提示以及优化用户体验在内的多个关键步骤。开发者可以利用提供的APK示例代码学习如何在项目中实现这一功能,并通过反编译工具深入理解代码细节。

weixin_42309599的博客 986

rawContact数据查询

对RawContacts主表可查询以下共18项数据: 变量名                                列名                                备注  _ID                                _id                                    这个就是raw_contact_id  CON

Robin Hu的专栏 2550

android Contacts 通讯录源码

android4.0 Contacts 通讯录源码

android 联系人模块

这是一个自己写的android联系人的app初学者可以学习

Pro Android学习笔记(一六十):联系人API(3):联系人数据

文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.youkuaiyun.com/flowingflying/以及作者@恺风Wei。 联系人信息 查看reference中android.provider.ContactsContract.CommonDataKinds可以知道该版本的Android API联系人中带有哪些信息。在API level 1

愷风(Wei)的专栏 7582

西门子WinCC VBS脚本实战:5分钟搞定变量记录导出到Excel(附完整代码)

本文提供了一套高效的西门子WinCC VBS脚本方案,帮助工程师在5分钟内将变量记录数据导出至Excel。方案详细解析了时区转换、数据库连接、SQL查询优化等核心难点,并附带了完整、可直接使用的VBS代码,解决了工业自动化项目中数据导出的实际痛点。

moss5的博客 609

如何将联系人从 iPhone 转移到安卓手机

综上所述,是最简单、高效、出错率最低的迁移方式。虽然蓝牙无法用于 iPhone 与安卓之间的数据传输,但你可以借助 iReaShare Phone Transfer 实现无缝迁移,兼顾速度、安全性和易用性。

Digitally的博客 2012

智能气象站:ESP32驱动的心知天气数据可视化实践

本文详细介绍了基于ESP32微控制器和心知天气API构建智能气象站的完整实践。通过Arduino开发环境,实现天气数据的获取、JSON解析与OLED屏可视化展示,涵盖硬件连接、API配置、低功耗优化及部署问题排查,为物联网开发者提供实用指南。

jump7的博客 210

Latex | IEEE双栏排版中长公式的排版

IEEE双栏排版中,有时候公式过于长了,过宽,导致单栏排版不下。

qq_43466146的博客 1万+

android联系人开发文档,Android联系人模块分析(一)

Android联系人模块分析(一)联系人模块是Android系统中的一个重要的功能模块,目前Android市场上有大量的基于通讯录的应用,本人计划写出系列文章详细介绍联系人模块的结构和使用。作为开头,本篇文章将对ContactsProvider做个简要的介绍。Android系统将联系人的信息存储在sqlite数据库中,并通过ContactsProvider提供查询、更新、删除等操作。所以如果需要掌...

weixin_39744384的博客 448

从理论到波形:NE555多谐振荡器设计与示波器实战验证

本文详细介绍了NE555多谐振荡器的设计原理与实战验证方法。从基础理论到电路参数计算,再到面包板搭建与示波器测量,全面解析如何利用NE555芯片实现稳定的方波输出。通过实际案例演示了频率调整、占空比优化等技巧,并提供了常见问题排查指南,帮助电子爱好者快速掌握这一经典电路设计。

weixin_29159613的博客 281

如何在Android上合并重复联系人?

要删除Android上的重复联系人,您可以直接在设备上使用方法1或方法3,尽管前者可能并非适用于所有设备。如果您更喜欢在不接触手机的情况下删除重复项,请在电脑上使用方法2。这篇文章对您有帮助吗?请在评论区分享您的反馈和建议。

Digitally的博客 1439

【11】GD32H7xx MPU记录

GD32H7xx系列MPU内存保护单元模块的使用记录

madao1234的博客 877

MIKE21 MIKE软件 教程 0.1 软件介绍与教学目录

MIKE 21是一个专业的工程软件包,用于模拟河流、湖泊、河口、海湾、海岸及海洋的水流、波浪、泥沙及环境问题。在MIKE Zero集成平台中,主要有MIKE11,MIKE21,MIKE3三类软件,分别对应一维,二维,三维的水动力模型模拟。同时还包括MIKE HYDRO,MIKE FLOOD等其他功能,各软件的具体介绍请参考DHI公司的官方文档,在此不作赘述。学习过程中,对于任何操作界面的疑问,建议大家仔细阅读帮助文档(在有疑问的界面按F1调出),同时官方也提供了对应的线上和线下教学服务(免费+收费)。

Hello Word 2万+

Android联系人模块分析(二)

上篇文章讲解了ContentsProvider的基本结构,本篇文章结合实际的联系人模块操作的例子来讲解联系人模块的使用。        下图为联系人模块中的表结构,各个表项中字段信息,可以参考上篇文章对ContactscProvder的分析中所描述的,在ContactsContract.java文件中定义了各个数据表的结构、Uri等信息。ContactsProvider数据库的三个主要的数据表结

jiang_lostcode的专栏 3392

24、汽车黑客技术全解析:诊断代码、车库创建与系统攻防

本文深入探讨了汽车黑客技术的核心内容,包括诊断代码模式与参数ID、创建开放车库社区、汽车系统相关技术、硬件与软件工具、攻击与防御手段,以及车辆通信与网络安全。无论你是汽车安全研究人员、爱好者还是开发者,都能从中获取全面的技术解析与实践指南。

Apple的专栏 228

浅谈android中手机联系人字母索引表的实现

实际上字母索引表的效果,可以说在现在的众多APP中使用的非常流行,比如支付宝,微信中的联系人,还有购物,买票的APP中选择全国城市,切换城市的时候,这时候的城市也就是按照一个字母索引的顺序来显示,看起来是很方便的.其实这种字母索引表的效果最开始是出现在微信的联系人中.因为觉得这种效果功能在今后的项目中可以说是非常常见,可能会用的上,所以准备来波博客讲述一下实现的原理,一来方便以后自己复习,二来如果

Mikyou的专栏 1万+

openbmc mctp i3c适配步骤

本文介绍了在Intel OKS平台下,BMC作为I3C从设备如何适配MCTP over I3C的实现方法。主要内容包括:1)关键术语解释,如MDB(Mandatory Data Byte)值为0xAE,DCR(Device Characteristics Register)和BCR(Bus Characteristics Register)的设置;2)适配流程说明,包括BMC作为控制器主节点分配地址后成为MCTP端点,CPU作为总线所有者的角色转换;3)测试验证步骤,展示通过mctp-client工具发送指

wit_yuan的专栏 132

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Android Contacts 联系人源码分析

http://www.lxway.com/161080401.htm Android Contacts总览 Contacts应用是由Google Android团队编写的Android原生应用。在应用层面上涉及到Contacts.apk, ContactProvider.apk。其他相关的在Framwork,以及framework与linux内核之间的SQLite.Contacts.a

happy_6678的专栏 2547

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

android T9 搜索联系人分析与实现(支持多音字)

最近在项目开发过程中

ZJQYJG的专栏 7903

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Android联系人模块分析(一)

联系人模块是Android系统中的一个重要的功能模块,目前Android市场上有大量的基于通讯录的应用,本人计划写出系列文章详细介绍联系人模块的结构和使用。作为开头,本篇文章将对ContactsProvider做个简要的介绍。      Android系统将联系人的信息存储在sqlite数据库中,并通过ContactsProvider提供查询、更新、删除等操作。所以如果需要掌握联系人相关信息的操

jiang_lostcode的专栏 3405

android 联系人界面,在Android4.0中Contacts添加联系人界面分析(源码)

一说到Contacts,那么最直接的就是怎样添加联系人?下面将从Android4.0代码的角度上描述一下增加联系人界面的初始化工作。请大家不要轻视这个初始化,因为其并不是想象中的setContentView就结束了的事。欲知详情,请听我详细道来。增加联系人界面的显示如下(图1,图2)图1 增加联系人界面1图2 增加联系人界面2看到上面的界面,您或许会想,也没啥嘛!我也不多说,一会您就知道了。通过...

weixin_34614567的博客 1258

删除联系人分析

3.2 删除联系人 Contacts相关模块中,有很多地方可以删除联系人,并且有单个删除联系人也有多个删除联系人。以QuickContactActivity为例论述删除单个联系人的详细流程, QuickContactActivity的界面如下, QuickContactActivity界面点击Delete菜单时,会弹出一个对话框,点击对话框的OK才会删除该联系人。 QuickCo

Jack的博客 1052

安卓获取联系人代码实例详解

直接看代码分析。注:本代码为引用。 import android.app.Activity; import android.database.Cursor; import android.os.Bundle; import android.provider.ContactsContract; import android.provider.ContactsContract.Data; impor

dahuzi的专栏 1249
上一篇: 根据gfp_mask来获得对应的zone
下一篇: Android编译系统
jiang_lostcode
博客等级 码龄18年 45粉丝 17原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值