作者:右心1477 | 来源:互联网 | 2023-10-15 16:54
本博客基于android7.1版本分析,仅用于沟通学习使用上一篇博客介绍了android导出vCard联系人流程紧接着我们在这篇博客来看看它是如何导入一个vCard
本博客基于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 /*** * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF* items *CRLF* "END" [ws] ":" [ws] "VCARD"*
* @return False when reaching end of file.*/ private boolean parseOneVCard () throws IOException, VCardException {mCurrentEncoding = DEFAULT_ENCODING; mCurrentCharset = DEFAULT_CHARSET; boolean allowGarbage = false ;if (!readBeginVCard(allowGarbage)) {return false ;}for (VCardInterpreter interpreter : mInterpreterList) {interpreter.onEntryStarted(); }parseItems();for (VCardInterpreter interpreter : mInterpreterList) {interpreter.onEntryEnded(); }return true ;}
protected boolean readBeginVCard (boolean allowGarbage) throws IOException, VCardException {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;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 + "\"" );}}