`
lucane
  • 浏览: 121649 次
  • 性别: Icon_minigender_1
  • 来自: 江湖
社区版块
存档分类
最新评论

解剖Android联系人之一,基于2.1

阅读更多
最近要做个联系人相关的东西,所以需要研究研究

Android的联系人数据结构比较不同,看起来比较混乱,作为新手来讲的我。

但还是得上啊,因为就我一个人

先看了几天的API,References,源码之类的(当然不是时时在看,这会儿翻翻,那会儿看看),比较迷糊,也有点理解,理解最多的就是他不是常理中想像的那样。

说到联系人,有个类不得不说,那就是ContactsContract,我是基于2.1看的,这个类有5000多行,也够多的

说实话,Android里面内部类,回调这些玩意用的太多了。。。

当然说了这么多的时候我还是不清楚联系人的结构

记得某位大神说的,理论不懂就实践,实践不懂就理论,我也比较喜欢这样,但我啥时候才能成为大神呢,至少是个小神吧

于是我开始实践,准备从数据库下手,它里面的数据最终是存在sqlite里面的,于是就要把这个数据库导出来瞧瞧

我开始想把我的Android Phone里的联系人给导出来,里面有些联系人的数据,或许可以用来分析,看下

但因为找不到数据线,就此作罢

于是开始导模拟器中的库,里面也是有数据的,是我测试的时候放进去的

位置位于/data/data/com.android.providers.contacts/databases/contacts2.db
不管是用命令adb pull,还是DDMS中的File Explorer都是可以导出到宿主机的
可能有些人上面这个文件的位置不一样,具体翻翻就知道他在哪了
然后就是sqlite3命令了
看客们不要高兴太早,我连自己都没有把握,接下来会是什么样子,我只是把这一个过程记录下来

$ sqlite3 contacts2.db
SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> 

看到有.help命令,当然第一个就是输入他了

sqlite> .help
.backup ?DB? FILE      Backup DB (default "main") to FILE
.bail ON|OFF           Stop after hitting an error.  Default OFF
.databases             List names and files of attached databases
.dump ?TABLE? ...      Dump the database in an SQL text format
                         If TABLE specified, only dump tables matching
                         LIKE pattern TABLE.
.echo ON|OFF           Turn command echo on or off
.exit                  Exit this program
.explain ?ON|OFF?      Turn output mode suitable for EXPLAIN on or off.
                         With no args, it turns EXPLAIN on.
.genfkey ?OPTIONS?     Options are:
                         --no-drop: Do not drop old fkey triggers.
                         --ignore-errors: Ignore tables with fkey errors
                         --exec: Execute generated SQL immediately
                       See file tool/genfkey.README in the source 
                       distribution for further information.
.header(s) ON|OFF      Turn display of headers on or off
.help                  Show this message
.import FILE TABLE     Import data from FILE into TABLE
.indices ?TABLE?       Show names of all indices
                         If TABLE specified, only show indices for tables
                         matching LIKE pattern TABLE.
.load FILE ?ENTRY?     Load an extension library
.log FILE|off          Turn logging on or off.  FILE can be stderr/stdout
.mode MODE ?TABLE?     Set output mode where MODE is one of:
                         csv      Comma-separated values
                         column   Left-aligned columns.  (See .width)
                         html     HTML <table> code
                         insert   SQL insert statements for TABLE
                         line     One value per line
                         list     Values delimited by .separator string
                         tabs     Tab-separated values
                         tcl      TCL list elements
.nullvalue STRING      Print STRING in place of NULL values
.output FILENAME       Send output to FILENAME
.output stdout         Send output to the screen
.prompt MAIN CONTINUE  Replace the standard prompts
.quit                  Exit this program
.read FILENAME         Execute SQL in FILENAME
.restore ?DB? FILE     Restore content of DB (default "main") from FILE
.schema ?TABLE?        Show the CREATE statements
                         If TABLE specified, only show tables matching
                         LIKE pattern TABLE.
.separator STRING      Change separator used by output mode and .import
.show                  Show the current values for various settings
.tables ?TABLE?        List names of tables
                         If TABLE specified, only list tables matching
                         LIKE pattern TABLE.
.timeout MS            Try opening locked tables for MS milliseconds
.width NUM1 NUM2 ...   Set column widths for "column" mode
.timer ON|OFF          Turn the CPU timer measurement on or off


出来的东西目前也不是很有用,就是一些命令的用法,其中有个命令是.table,这是我们需要的,他这里的命令前面都是带dot symbol的,该死的,网络又断了,这么不给力的网

sqlite> .tables
_sync_state                       status_updates                  
_sync_state_metadata              v1_settings                     
activities                        view_contacts                   
agg_exceptions                    view_contacts_restricted        
android_metadata                  view_data                       
calls                             view_data_restricted            
contact_entities_view             view_groups                     
contact_entities_view_restricted  view_raw_contacts               
contacts                          view_raw_contacts_restricted    
data                              view_v1_contact_methods         
groups                            view_v1_extensions              
mimetypes                         view_v1_group_membership        
name_lookup                       view_v1_groups                  
nickname_lookup                   view_v1_organizations           
packages                          view_v1_people                  
phone_lookup                      view_v1_phones                  
raw_contacts                      view_v1_photos                  
settings                        


这下面一共有这么多表

前几天还是看过一些资料的,ContactsContract有很多个内部类,其中有Data,RawContacts,Contacts之类的
这表里面也有类似的这几个表,当然都要打开看看咯

sqlite> select * from contacts;
1|海 郭|||0|0|0|0|1|1|0nE044748D16||0


sqlite> select * from raw_contacts;  
1|0||||2|1|0|1|0|0||0|0||0|海 郭|40||||


sqlite> select * from data;
1||4|1|0|0|0|坏人|1|||||||||||||||||
2||5|1|0|0|0|http://lucane.iteye.com|7|||||||||||||||||
3||3|1|0|0|0|长板坡宜昌, 湖北 443200|1||长板坡|||宜昌|湖北|443200||||||||||
4||6|1|0|0|0|非人||||||||||||||||||
5||7|1|0|0|0|1-504-115-9854|1||45895114051|||||||||||||||
6||7|1|0|0|0|1-226-548-89|2||988456221|||||||||||||||
7||2|1|0|0|0|304683630|3|||4||||||||||||||
8||8|1|0|0|0|home|1||翻译官|||||||||||||||
9||9|1|0|0|0|海 郭|海|郭||||||||||||||||
10||1|1|0|0|0|xscript#live.com|2|||||||||||||||||
11||1|1|0|0|0|xseaer#gmail.com|1|||||||||||||||||


这都是我自己的的信息,真真假假,假假真真
命令行看着不怎么清晰,我前几天还在找和安装sqlite的图形化界面,结果未遂

可能新手看官看不出来啥东西,不过我有点看清楚了,因为我知道这有些数据项是什么意思

当然这所有的表当中可能还有些是视图,感兴趣的也可以都select出来看看

当然这还有些表是要select出来看的,比如mimetypes,

sqlite> select * from mimetypes;
1|vnd.android.cursor.item/email_v2
2|vnd.android.cursor.item/im
3|vnd.android.cursor.item/postal-address_v2
4|vnd.android.cursor.item/nickname
5|vnd.android.cursor.item/website
6|vnd.android.cursor.item/note
7|vnd.android.cursor.item/phone_v2
8|vnd.android.cursor.item/organization
9|vnd.android.cursor.item/name
10|vnd.android.cursor.item/photo
11|vnd.android.cursor.item/group_membership


sqlite> select * from view_data;
1|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/nickname|坏人|1|||||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
2|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/website|http://lucane.iteye.com|7|||||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
3|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/postal-address_v2|长板坡宜昌, 湖北 443200|1||长板坡|||宜昌|湖北|443200||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
4|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/note|非人||||||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
5|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/phone_v2|1-504-115-9854|1||45895114051|||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
6|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/phone_v2|1-226-548-89|2||988456221|||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
7|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/im|304683630|3|||4||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
8|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/organization|home|1||翻译官|||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
9|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/name|海 郭|海|郭||||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
10|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/email_v2|xscript#live.com|2|||||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
11|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/email_v2|xseaer#gmail.com|1|||||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||


比如看到view_data里面的数据是不是又有点开心了呢?

顺路把其他几个view也查处来看看吧

sqlite> select * from view_contacts;
1||海 郭|1|1|0nE044748D16||1|0|0|0|0|


sqlite> select * from view_contacts_restricted;
1||海 郭|1|1|0nE044748D16||1|0|0|0|0|


sqlite> select * from view_data_restricted;
1|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/nickname|坏人|1|||||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
2|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/website|http://lucane.iteye.com|7|||||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
3|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/postal-address_v2|长板坡宜昌, 湖北 443200|1||长板坡|||宜昌|湖北|443200||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
4|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/note|非人||||||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
5|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/phone_v2|1-504-115-9854|1||45895114051|||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
6|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/phone_v2|1-226-548-89|2||988456221|||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
7|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/im|304683630|3|||4||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
8|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/organization|home|1||翻译官|||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
9|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/name|海 郭|海|郭||||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
10|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/email_v2|xscript#live.com|2|||||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||
11|1|1||||2|1|||||0|0|0||vnd.android.cursor.item/email_v2|xseaer@#mail.com|1|||||||||||||||||||0|0|0|0|海 郭|0nE044748D16||1||


比较让我失望的是android_metadata,settings这些表当中没有查询出什么数据
因为我总觉得这些mimetypes什么的应该和某个数字或字符相对应(后来发现了mimetypes中的文字就是和该表当中貌似第一列主键的这个东西对应的,在其他的表中也是直接存的这个数字)

恩,接着再往下看吧,该搞那块了?

这些表当中数据的存放不是通常的一个字段对应下面的数据都是这个意思,比如username字段下的数据都是用户名

在data表当中,至少我们现在可以明显的看出来在data表中,每行数据有指定他的类型,说他是什么,他就是什么

用原话来说基本就是这样Generic data column, the meaning is {@link #MIMETYPE} specific
大概可能就是说当每一条数据的MIMETYPE定了,那么它每一列代表的含义也就定了

这种方式大概就是为了扩展的需要吧,当年我们也有这么干的时候

不知道大家对这个查询出来的数据有没有和我们平时不同的感觉
我感觉它缺了个title,虽然他的title含义不是固定的,但我总想看看

于是想把他弄出来看看
还记得我们最开始的时候.help出来有很多命令,我们只用了.table这个最关键的
既然想看表的结构么,当然就是desc或者describe这些命令了,不才我虽然正式开始Rock Android才不久,但是以前还是搞SSH的,Oracle和MySQL还是略懂一二的

不过没有发现类似的命令,倒是发现了个.schema(Show the CREATE statements)命令,既然图形化的看不见,看SQL也是一样的

sqlite> .schema 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,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 );
CREATE INDEX data_mimetype_data1_index ON data (mimetype_id,data1);
CREATE INDEX data_raw_contact_id ON data (raw_contact_id);
CREATE TRIGGER data_deleted BEFORE DELETE ON data BEGIN    UPDATE raw_contacts     SET version=version+1      WHERE _id=OLD.raw_contact_id;   DELETE FROM phone_lookup     WHERE data_id=OLD._id;   DELETE FROM status_updates     WHERE status_update_data_id=OLD._id;   DELETE FROM name_lookup     WHERE data_id=OLD._id; END;
CREATE TRIGGER data_updated BEFORE UPDATE ON data BEGIN    UPDATE data     SET data_version=OLD.data_version+1      WHERE _id=OLD._id;   UPDATE raw_contacts     SET version=version+1      WHERE _id=OLD.raw_contact_id; END;


好长啊,又是表,又是索引,又是触发器,这么一个小数据库开是挺专业的
好吧,既然没有图形化的,我手动给他画个,刷个牙,回来再继续,晚上10点半了

引用
_id  package_id  mimetype_id  raw_contact_id  is_primary  is_super_primary  data_version  data1  data2  data3  data4  data5  data6  data7  data8  data9  data10  data11  data12  data13  data14  data15  data_sync1  data_sync2  data_sync3  data_sync4


这就是这个表所有的列了,我们把它变换下
引用
_id  package_id  mimetype_id  raw_contact_id  is_primary  is_super_primary  data_version  data_sync1 ...... data_sync4  data1 ...... data15

上面这行的“ ...... ”是我自己干的,没有什么意义,只是想让看的更清楚点,他们都省略了前后值之间的下标的一些项,相信你懂的
随便找几条数据来比着看下吧
引用
5||7|1|0|0|0|1-504-115-9854|1||45895114051|||||||||||||||
7||2|1|0|0|0|304683630|3|||4||||||||||||||
8||8|1|0|0|0|home|1||翻译官|||||||||||||||
9||9|1|0|0|0|海 郭|海|郭||||||||||||||||
10||1|1|0|0|0|xscript#live.com|2|||||||||||||||||
11||1|1|0|0|0|xseaer#gmail.com|1|||||||||||||||||


有个字段中他把电话号码做了个reverse,神马意图?

再来一个变换
引用
_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            
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


再看看创建的两个索引
CREATE INDEX data_mimetype_data1_index ON data (mimetype_id,data1);
CREATE INDEX data_raw_contact_id ON data (raw_contact_id);

我们可以猜测是为了加快查询速度吧
那么data1一般保存的是啥数据,看起来应该挺关键的
mimetype_id和raw_contact_id应该比较好理解,前面的就相当于类型分类,后面的可能是个类似于主键之类的东西吧
一般貌似在代码中首先查询个这个东西出来,然后再去查询其他的

再来看看触发器
CREATE TRIGGER data_deleted BEFORE DELETE ON data
 BEGIN 
   UPDATE raw_contacts 
    SET version=version+1
      WHERE _id=OLD.raw_contact_id;
   DELETE FROM phone_lookup
     WHERE data_id=OLD._id;
   DELETE FROM status_updates
     WHERE status_update_data_id=OLD._id;
   DELETE FROM name_lookup
     WHERE data_id=OLD._id;
 END;

CREATE TRIGGER data_updated BEFORE UPDATE ON data
 BEGIN
    UPDATE data
     SET data_version=OLD.data_version+1
      WHERE _id=OLD._id;
    UPDATE raw_contacts
     SET version=version+1
      WHERE _id=OLD.raw_contact_id;
 END;


不知道我这么给他排版对不对,应该是这样的吧
第一个大概意思是对data表中的数据进行DELETE操作的时候,要更新raw_contacts表中的version字段数据,要删除phone_lookup中的数据,要删除status_updates中的数据,要删除name_lookup中的数据
这个OLD是个神马东西,先不管了
第二个更简单,就是说更新data表中的数据的时候,要更新data表的version字段数据,要更新raw_contacts表的version字段数据
这些version字段等的更新都是加一操作

这应该可以说明联系人信息的修改会被记录下来,这正是我要的,因为要做一个同步程序,虽然我也看过别人很多开源的代码,但都还是迷迷糊糊的

data表拆完了,再来拆contacts和raw_contacts表看看,都是体力劳动
高手们就直接会下个或者自己写个图形化的客户端来搞

头脑发晕了,在.schema contacts后面多打了个分号,结果不报错,也啥都不显示。。。

sqlite> .schema contacts
CREATE TABLE contacts (_id INTEGER PRIMARY KEY AUTOINCREMENT,display_name TEXT,photo_id INTEGER REFERENCES data(_id),custom_ringtone TEXT,send_to_voicemail INTEGER NOT NULL DEFAULT 0,times_contacted INTEGER NOT NULL DEFAULT 0,last_time_contacted INTEGER,starred INTEGER NOT NULL DEFAULT 0,in_visible_group INTEGER NOT NULL DEFAULT 1,has_phone_number INTEGER NOT NULL DEFAULT 0,lookup TEXT,status_update_id INTEGER REFERENCES data(_id),single_is_restricted INTEGER NOT NULL DEFAULT 0);
CREATE INDEX contacts_has_phone_index ON contacts (has_phone_number);
CREATE INDEX contacts_restricted_index ON contacts (single_is_restricted);
CREATE INDEX contacts_visible_index ON contacts (in_visible_group,display_name COLLATE LOCALIZED);
CREATE TRIGGER contacts_times_contacted UPDATE OF last_time_contacted ON contacts BEGIN UPDATE contacts SET times_contacted = (new.times_contacted + 1) WHERE _id = new._id;END;


表头
引用
_id  display_name  photo_id  custom_ringtone  send_to_voicemail  times_contacted  last_time_contacted  starred  in_visible_group  has_phone_number  lookup  status_update_id  single_is_restricted


对比数据
引用
1 | 海 郭 |  |  | 0 | 0 | 0 | 0 | 1 | 1 | 0nE044748D16 |  | 0


如此变换
引用
_id                             INTEGER PRIMARY KEY AUTOINCREMENT
display_name                    TEXT
photo_id                        INTEGER REFERENCES data(_id)
custom_ringtone                 TEXT
send_to_voicemail               INTEGER NOT NULL DEFAULT 0
times_contacted                 INTEGER NOT NULL DEFAULT 0
last_time_contacted             INTEGER
starred                         INTEGER NOT NULL DEFAULT 0
in_visible_group                INTEGER NOT NULL DEFAULT 1
has_phone_number                INTEGER NOT NULL DEFAULT 0
lookup                          TEXT
status_update_id                INTEGER REFERENCES data(_id)
single_is_restricted            INTEGER NOT NULL DEFAULT 0

三条索引
CREATE INDEX contacts_has_phone_index ON contacts (has_phone_number);
CREATE INDEX contacts_restricted_index ON contacts (single_is_restricted);
CREATE INDEX contacts_visible_index ON contacts (in_visible_group,display_name COLLATE LOCALIZED);

一个触发器
CREATE TRIGGER contacts_times_contacted UPDATE OF last_time_contacted ON contacts
 BEGIN
  UPDATE contacts
   SET times_contacted = (new.times_contacted + 1)
    WHERE _id = new._id;
 END;

这个就是当最后一次联系时间变了,就把联系次数加一
应该就是给这个人打过一次电话了,这个次数就会增加一

剩下raw_contacts,继续
sqlite> .schema raw_contacts
CREATE TABLE raw_contacts (_id INTEGER PRIMARY KEY AUTOINCREMENT,is_restricted INTEGER DEFAULT 0,account_name STRING DEFAULT NULL, account_type STRING DEFAULT NULL, sourceid TEXT,version INTEGER NOT NULL DEFAULT 1,dirty INTEGER NOT NULL DEFAULT 0,deleted INTEGER NOT NULL DEFAULT 0,contact_id INTEGER REFERENCES contacts(_id),aggregation_mode INTEGER NOT NULL DEFAULT 0,aggregation_needed INTEGER NOT NULL DEFAULT 1,custom_ringtone TEXT,send_to_voicemail INTEGER NOT NULL DEFAULT 0,times_contacted INTEGER NOT NULL DEFAULT 0,last_time_contacted INTEGER,starred INTEGER NOT NULL DEFAULT 0,display_name TEXT,display_name_source INTEGER NOT NULL DEFAULT 0,sync1 TEXT, sync2 TEXT, sync3 TEXT, sync4 TEXT );
CREATE INDEX raw_contacts_contact_id_index ON raw_contacts (contact_id);
CREATE INDEX raw_contacts_source_id_index ON raw_contacts (sourceid, account_type, account_name);
CREATE TRIGGER raw_contacts_deleted    BEFORE DELETE ON raw_contacts BEGIN    DELETE FROM data     WHERE raw_contact_id=OLD._id;   DELETE FROM agg_exceptions     WHERE raw_contact_id1=OLD._id        OR raw_contact_id2=OLD._id;   DELETE FROM contacts     WHERE _id=OLD.contact_id       AND (SELECT COUNT(*) FROM raw_contacts            WHERE contact_id=OLD.contact_id           )=1; END;
CREATE TRIGGER raw_contacts_marked_deleted    BEFORE UPDATE ON raw_contacts BEGIN    UPDATE raw_contacts     SET version=OLD.version+1      WHERE _id=OLD._id       AND NEW.deleted!= OLD.deleted; END;
CREATE TRIGGER raw_contacts_times_contacted UPDATE OF last_time_contacted ON raw_contacts BEGIN UPDATE raw_contacts SET times_contacted = (new.times_contacted + 1) WHERE _id = new._id;END;


表头
引用
id  is_restricted  account_name  account_type  sourceid  version  dirty  deleted  contact_id  aggregation_mode  aggregation_needed  custom_ringtone  send_to_voicemail  times_contacted  last_time_contacted  starred  display_name  display_name_source  sync1  sync2  sync3  sync4


对比数据
引用
1 | 0 |  |  |  | 2 | 1 | 0 | 1 | 0 | 0 |  | 0 | 0 |  | 0 | 海 郭 | 40 |  |  |  |


如此变换
引用
id                                          INTEGER PRIMARY KEY AUTOINCREMENT
is_restricted                               INTEGER DEFAULT 0
account_name                                STRING DEFAULT NULL
account_type                                STRING DEFAULT NULL
sourceid                                    TEXT
version                                     INTEGER NOT NULL DEFAULT 1
dirty                                       INTEGER NOT NULL DEFAULT 0
deleted                                     INTEGER NOT NULL DEFAULT 0
contact_id                                  INTEGER REFERENCES contacts(_id)
aggregation_mode                            INTEGER NOT NULL DEFAULT 0
aggregation_needed                          INTEGER NOT NULL DEFAULT 1
custom_ringtone                             TEXT
send_to_voicemail                           INTEGER NOT NULL DEFAULT 0
times_contacted                             INTEGER NOT NULL DEFAULT 0
last_time_contacted                         INTEGER
starred                                     INTEGER NOT NULL DEFAULT 0
display_name                                TEXT
display_name_source                         INTEGER NOT NULL DEFAULT 0
sync1                                       TEXT
sync2                                       TEXT
sync3                                       TEXT
sync4                                       TEXT


两个索引
CREATE INDEX raw_contacts_contact_id_index ON raw_contacts (contact_id);
CREATE INDEX raw_contacts_source_id_index ON raw_contacts (sourceid, account_type, account_name);

三个触发器
CREATE TRIGGER raw_contacts_deleted
   BEFORE DELETE ON raw_contacts
 BEGIN 
   DELETE FROM data
     WHERE raw_contact_id=OLD._id;
   DELETE FROM agg_exceptions
     WHERE raw_contact_id1=OLD._id
        OR raw_contact_id2=OLD._id;
   DELETE FROM contacts
     WHERE _id=OLD.contact_id
       AND (SELECT COUNT(*) FROM raw_contacts
            WHERE contact_id=OLD.contact_id
           )=1;
 END;

CREATE TRIGGER raw_contacts_marked_deleted
    BEFORE UPDATE ON raw_contacts BEGIN
    UPDATE raw_contacts
     SET version=OLD.version+1
      WHERE _id=OLD._id
       AND NEW.deleted!= OLD.deleted;
 END;

CREATE TRIGGER raw_contacts_times_contacted UPDATE OF last_time_contacted ON raw_contacts
 BEGIN
 UPDATE raw_contacts
   SET times_contacted = (new.times_contacted + 1)
     WHERE _id = new._id;
 END;


这就是三个主要表的东西,写了这么多,都是体力活,当然还有很多不是很清楚,但也有点点进步了
接下来该干啥了,该睡觉了,明天或者后天,或者大后天继续

下一步就是修改联系人数据,然后再导份出来看下,结合API看看


UPDATE 2011-06-08

可视化操作数据库工具
我在Ubuntu下用的是SQLITEMAN,Ubuntu最简单的安装办法就是sudo apt-get install sqliteman,还不错,供我们查看数据已经足够了,还有人就直接在Android上装的软件查看的,那个也行,但就屏幕太小了

联系人本身的逻辑理解了还是很简单的,当时做的时候遇到的最大的问题就是效率问题
面对2000+条联系人怎么让读写更快,传输的数据最小,确实比较费事
读写最快的原则就是尽量少开关数据库,将数据放缓存,缓存又会占用内存,这是个很矛盾的问题

另外如果没有获取ROOT权限的真机是没有办法查看到/data/目录下面的内容的,手机厂家是出于安全因素考虑,所以当时即使我找到了数据线也没有办法直接看里面的内容

貌似有些问题到现在都还没有解决的很彻底又被拉去干别的事情去了。。。
分享到:
评论
1 楼 to_zoe_yang 2011-06-08  
很强大啊~

相关推荐

    基于Android平台的校园通软件毕业论文.doc

    【基于Android平台的校园通软件】毕业论文主要探讨了如何利用Android操作系统开发一款适用于校园环境的通用软件。本文首先从国内外手机系统的发展现状及其应用情况出发,分析了Android平台在移动应用开发中的重要...

    探讨基于移动互联网的人体解剖学第二课堂建设.pdf

    探讨基于移动互联网的人体解剖学第二课堂建设.pdf

    最全人体解剖图

    在探讨“最全人体解剖图”这一主题时,我们实际上是在深入研究人体结构的奥秘,这不仅是医学教育的基础,也是法医学、生物科学、艺术创作等多个领域不可或缺的知识体系。解剖学作为一门研究生物体各部分结构的学科,...

    最全,最经典的人体解剖图.

    根据提供的文件信息,这里将基于“最全,最经典的人体解剖图”这一主题进行展开,探讨人体解剖学中的关键知识点。 ### 一、人体解剖学概述 人体解剖学是研究人体结构的一门学科,它帮助我们了解身体各部位的位置、...

    3D人体解剖图

    在医学教育的众多领域中,解剖学无疑是最为基础且关键的学科之一。了解人体的结构、组织以及器官的工作原理是任何医生、护士、康复治疗师乃至医学生必须掌握的基本知识。随着科技的进步,传统的解剖学习方式也在发生...

    人体解剖学习题集(含答案).pdf

    《人体解剖学习题集(含答案).pdf》就是一本专门针对人体骨学设计的练习册,它通过精选的习题,为学习者提供了一个理解和记忆解剖结构的有效工具。 骨学是人体解剖学中非常重要的一个分支,它不仅要求学习者熟悉每...

    人体断面与影像解剖学盆部与会阴之一PPT学习教案.pptx

    人体断面与影像解剖学盆部与会阴之一PPT学习教案.pptx

    three. js的人体解剖图.zip

    Three.js 是一个基于 WebGL 的 JavaScript 库,它为Web开发人员提供了一个在浏览器中创建3D图形的强大工具。这个“three.js的人体解剖图”压缩包,很显然是一个利用Three.js库来展示人体结构的3D可视化项目。下面...

    3d针炙穴位图(人体解剖图)

    根据给定文件的信息,本文将围绕“3D针灸穴位图(人体解剖图)”这一主题进行深入探讨。此PDF文档为转载作品,并非商业用途,而是出于分享的精神。以下将详细介绍与该主题相关的知识点。 ### 一、3D人体解剖学软件 ...

    论文研究 - 在基于尸体的解剖学复习课程中,对护士麻醉师和理疗师进行跨专业教育经历的学生观点

    背景:越来越多的证据支持不同医学专业的学生跨专业教育(IPE... 百分之一百的CRNA学生发现以尸体为基础的解剖学课程是有益的,并认为该课程增强了他们对人体解剖学的三维理解,他们认为这对将来的麻醉程序将是有益的。

    人体解剖浏览器MediView

    在CG(Computer Graphics,计算机图形学)领域,MediView是一款极具价值的工具,专为学习和理解人体解剖学设计。这款软件利用先进的三维技术和360度观看功能,提供了一个直观、立体的观察平台,使用户能够从各个角度...

    人体解剖三维动画

    【压缩包子文件的文件名称】"3dBody解剖软件"表明这是一个专门用于人体解剖学习的应用程序。3D Body软件很可能提供了详尽的人体模型库,用户可以通过触摸屏操作或者键盘鼠标进行交互,旋转、放大、缩小模型,查看...

    人体解剖软件

    用户可以自由缩放、旋转、切割模型,深入到微观层面去观察每个细节,如同拥有了一把虚拟的解剖刀。这种体验极大地提升了学习者的理解和记忆效果,也使得教学过程更加生动和高效。 此外,3dBody软件还提供了丰富的...

    C语言深度解剖.pdf

    ### C语言深度解剖知识点解析 #### 一、引言:C语言的重要性及现状分析 在当前快速发展的信息技术领域中,编程语言作为实现各种软件应用的基础工具,扮演着至关重要的角色。C语言作为一门历史悠久且功能强大的编程...

    基于3D技术的解剖学信息化教学设计.pdf

    "基于3D技术的解剖学信息化教学设计"是一个创新的教学方法,旨在利用现代科技提升学生的学习体验和理解深度。 首先,3D技术的应用使得解剖学的教学更加直观和生动。传统的解剖学教学通常依赖于二维的教科书插图或...

    3D人体解剖高清图谱.pdf

    目前见过的高清3D人体模型最好的一个了,截图供大家欣赏,这个可能我通过微信传的时候像素有损失,大家大量,我截取的当然也只有平面图,3D的...3D人体解剖高清图谱,人体骨骼解剖图,人体腹部解剖图,女性人体解剖图,

Global site tag (gtag.js) - Google Analytics