版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/michael_yt/article/details/78299536
本博客基于android7.1版本分析,仅用于沟通学习使用
上一篇博客介绍了 android导出vCard联系人流程 紧接着我们在这篇博客来看看它是如何导入一个vCard联系人的。
整体流程总结
- 通过在contacts联系人中界面跳转,我们跳转到了 DocumentsActivity 界面并选择我们需要导入的以 .vcf 结尾的vCard文件,将Uri以intent的方式返回给ImportVCardActivity。
- 通过readUriToLocalUri方法将uri指向的文件copy到本地临时目录。
- 启动一个线程开始解析文件,并指定vCard类型为 text/x-vcard 版本为2.1,后面就只会创建2.1版本对应的解析器,所以其它版本的vCard导入可能会出现问题。
- 然后通过VCardParserImpl_V21来具体解析文件中的每一行,最后通过VCardEntryCommitter.pushIntoContentResolver批量插入contacts的数据库
几个重点类的作用
- ImportVCardActivity : 一个中间控制类,它控制了界面dialog、notification、service、thread的启动和消失
- VCardParserImpl_V21 : 负责vCard2.1版本内容的逐行解析
- VCardEntryConstructor : 负责将解析出来的数据以VCardEntry的形式暂存在内存中
- VCardEntryCommitter : 负责将解析出来的数据存储到contacts数据库中
整体操作图
整体流程图
部分重点方法介绍
VCardParserImpl_V21
/**
* <code>
* vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
* items *CRLF
* "END" [ws] ":" [ws] "VCARD"
* </code>
* @return False when reaching end of file.
*/
private boolean parseOneVCard() throws IOException, VCardException {
// reset for this entire vCard.
mCurrentEncoding = DEFAULT_ENCODING; //8BIT
mCurrentCharset = DEFAULT_CHARSET; //UTF-8
boolean allowGarbage = false;
if (!readBeginVCard(allowGarbage)) {
return false;
}
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onEntryStarted(); //解析vCard中一个联系人开始标志
}
parseItems();//逐行解析
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onEntryEnded(); //解析完vCard中一个联系人结束标志
}
return true;
}
protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException {
// TODO: use consructPropertyLine().
String line;
do {
while (true) {
line = getLine();
if (line == null) {
return false;
} else if (line.trim().length() > 0) {
break;
}
}
final String[] strArray = line.split(":", 2);
final int length = strArray.length;
// Although vCard 2.1/3.0 specification does not allow lower cases,
// we found vCard file emitted by some external vCard expoter have such
// invalid Strings.
// e.g. BEGIN:vCard
if (length == 2 && strArray[0].trim().equalsIgnoreCase("BEGIN")
&& strArray[1].trim().equalsIgnoreCase("VCARD")) { //判断是否是开头?
return true;
} else if (!allowGarbage) {
throw new VCardException("Expected String \"BEGIN:VCARD\" did not come "
+ "(Instead, \"" + line + "\" came)");
}
} while (allowGarbage);
throw new VCardException("Reached where must not be reached.");
}
/*
* item = [groups "."] name [params] ":" value CRLF / [groups "."] "ADR"
* [params] ":" addressparts CRLF / [groups "."] "ORG" [params] ":" orgparts
* CRLF / [groups "."] "N" [params] ":" nameparts CRLF / [groups "."]
* "AGENT" [params] ":" vcard CRLF
*/
protected boolean parseItem() throws IOException, VCardException {
// Reset for an item.
mCurrentEncoding = DEFAULT_ENCODING;
final String line = getNonEmptyLine();
final VCardProperty propertyData = constructPropertyData(line);
final String propertyNameUpper = propertyData.getName().toUpperCase();
final String propertyRawValue = propertyData.getRawValue();
if (propertyNameUpper.equals(VCardConstants.PROPERTY_BEGIN)) {
if (propertyRawValue.equalsIgnoreCase("VCARD")) {
handleNest();
} else {
throw new VCardException("Unknown BEGIN type: " + propertyRawValue);
}
} else if (propertyNameUpper.equals(VCardConstants.PROPERTY_END)) {
if (propertyRawValue.equalsIgnoreCase("VCARD")) {
return true; // Ended.
} else {
throw new VCardException("Unknown END type: " + propertyRawValue);
}
} else {
parseItemInter(propertyData, propertyNameUpper);
}
return false;
}
private void parseItemInter(VCardProperty property, String propertyNameUpper)
throws IOException, VCardException {
String propertyRawValue = property.getRawValue();
if (propertyNameUpper.equals(VCardConstants.PROPERTY_AGENT)) {
handleAgent(property);
} else if (isValidPropertyName(propertyNameUpper)) {
if (propertyNameUpper.equals(VCardConstants.PROPERTY_VERSION) &&
!propertyRawValue.equals(getVersionString())) {
throw new VCardVersionException(
"Incompatible version: " + propertyRawValue + " != " + getVersionString());
}
handlePropertyValue(property, propertyNameUpper); //解析里面每个属性
} else {
throw new VCardException("Unknown property name: \"" + propertyNameUpper + "\"");
}
}