当前位置: 代码迷 >> Android >> Android 使用VCard数据类型 异步开展联系人备份与恢复操作
  详细解决方案

Android 使用VCard数据类型 异步开展联系人备份与恢复操作

热度:112   发布时间:2016-04-24 11:16:56.0
Android 使用VCard数据类型 异步进行联系人备份与恢复操作

生活中常有人因为更换手机而丢失联系人信息,又需要重新一个个去找亲戚朋友获取。
这样的情况下,联系人备份与恢复功能就显得非常实用。所以我学习了相关内容,并进行了适当整合,在这里整理出来。

本篇博客两个重点

  1. 使用VCard库进行联系人备份与恢复
  2. 异步进行备份与恢复操作

为什么要用VCard?

VCard是用于联系人数据存储的标准数据格式,且有一套已经成熟的库可以使用,通用于手机,也通用于邮件等,所以使用VCard进行联系人的数据存储与备份格式是非常好的选择。当然是用XML格式去存储也是可以的。

下载android-vcard.jar请猛戳这里

为什么要异步进行操作?

联系人备份与恢复都涉及到了数据库读写,而数据库的操作一向都是比较费时的,更何况是大量数据的情况下,所以将这些操作进行异步处理是一个非常有必要的事情,否则容易造成UI主线程卡顿。异步的另一个好处是同时能够在UI界面上给用户一些过程进度上的反馈,这个在重视产品交互体验的今天是非常重要的。

一个异步操作UI效果库,源自GitHub请猛戳这里

VCard本身库比较复杂,不再多说,有兴趣的可以研究源码。这里贴上一个已经做过一层封装的联系人处理类,直接集成调用即可。

封装好的联系人处理类model

package com.pku.codingma.backupandrecovercontactdemo;import android.app.Activity;import android.content.ContentUris;import android.content.ContentValues;import android.database.Cursor;import android.net.Uri;import android.os.Environment;import android.provider.ContactsContract;import java.io.BufferedReader;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.List;import a_vcard.android.provider.Contacts;import a_vcard.android.syncml.pim.VDataBuilder;import a_vcard.android.syncml.pim.VNode;import a_vcard.android.syncml.pim.vcard.ContactStruct;import a_vcard.android.syncml.pim.vcard.VCardComposer;import a_vcard.android.syncml.pim.vcard.VCardException;import a_vcard.android.syncml.pim.vcard.VCardParser;/** * Created by ma on 2016/4/1. */public class ContactInfo {    /**     * MUST exist     */    private String name; // 姓名    /**     * 联系人电话信息     */    public static class PhoneInfo {        /**         * 联系电话类型         */        public int type;        /**         * 联系电话         */        public String number;    }    /**     * 联系人邮箱信息     */    public static class EmailInfo {        /**         * 邮箱类型         */        public int type;        /**         * 邮箱         */        public String email;    }    private List<PhoneInfo> phoneList = new ArrayList<PhoneInfo>(); // 联系号码    private List<EmailInfo> email = new ArrayList<EmailInfo>(); // Email    /**     * 构造联系人信息     *     * @param name 联系人姓名     */    public ContactInfo(String name) {        this.name = name;    }    /**     * 姓名     */    public String getName() {        return name;    }    /**     * 姓名     */    public ContactInfo setName(String name) {        this.name = name;        return this;    }    /**     * 联系电话信息     */    public List<PhoneInfo> getPhoneList() {        return phoneList;    }    /**     * 联系电话信息     */    public ContactInfo setPhoneList(List<PhoneInfo> phoneList) {        this.phoneList = phoneList;        return this;    }    /**     * 邮箱信息     */    public List<EmailInfo> getEmail() {        return email;    }    /**     * 邮箱信息     */    public ContactInfo setEmail(List<EmailInfo> email) {        this.email = email;        return this;    }    @Override    public String toString() {        return "{name: " + name + ", number: " + phoneList + ", email: " + email + "}";    }}

封装在ContactInfo内部的操作handler类

/**     * 联系人     * 备份/还原操作     *     */    public static class ContactHandler {        private static ContactHandler instance_ = new ContactHandler();        /**         * 获取实例         */        public static ContactHandler getInstance() {            return instance_;        }     }

通过数据库获取手机中的联系人

        /**         * 获取联系人指定信息         *         * @param projection 指定要获取的列数组, 获取全部列则设置为null         * @return         * @throws Exception         */        public Cursor queryContact(Activity context, String[] projection) {            // 获取联系人的所需信息            Cursor cur = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, projection, null, null, null);            return cur;        }        /**         * 获取联系人信息         *         * @param context         * @return         */        public List<ContactInfo> getContactInfo(Activity context) {            List<ContactInfo> infoList = new ArrayList<ContactInfo>();            Cursor cur = queryContact(context, null);            if (cur.moveToFirst()) {                do {                    // 获取联系人id号                    String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));                    // 获取联系人姓名                    String displayName = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));                    ContactInfo info = new ContactInfo(displayName);// 初始化联系人信息                    // 查看联系人有多少电话号码, 如果没有返回0                    int phoneCount = cur.getInt(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));                    if (phoneCount > 0) {                        Cursor phonesCursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + id, null, null);                        if (phonesCursor.moveToFirst()) {                            List<PhoneInfo> phoneNumberList = new ArrayList<PhoneInfo>();                            do {                                // 遍历所有电话号码                                String phoneNumber = phonesCursor.getString(phonesCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));                                // 对应的联系人类型                                int type = phonesCursor.getInt(phonesCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));                                // 初始化联系人电话信息                                ContactInfo.PhoneInfo phoneInfo = new ContactInfo.PhoneInfo();                                phoneInfo.type = type;                                phoneInfo.number = phoneNumber;                                phoneNumberList.add(phoneInfo);                            } while (phonesCursor.moveToNext());                            // 设置联系人电话信息                            info.setPhoneList(phoneNumberList);                        }                    }                    // 获得联系人的EMAIL                    Cursor emailCur = context.getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + "=" + id, null, null);                    if (emailCur.moveToFirst()) {                        List<EmailInfo> emailList = new ArrayList<EmailInfo>();                        do {                            // 遍历所有的email                            String email = emailCur.getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA1));                            int type = emailCur.getInt(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE));                            // 初始化联系人邮箱信息                            ContactInfo.EmailInfo emailInfo = new ContactInfo.EmailInfo();                            emailInfo.type = type;    // 设置邮箱类型                            emailInfo.email = email;    // 设置邮箱地址                            emailList.add(emailInfo);                        } while (emailCur.moveToNext());                        info.setEmail(emailList);                    }                    //Cursor postalCursor = getContentResolver().query(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_URI, null, ContactsContract.CommonDataKinds.StructuredPostal.CONTACT_ID + "=" + id, null, null);                    infoList.add(info);                } while (cur.moveToNext());            }            cur.close();            return infoList;        }

将获取到的联系人数据通过VCard数据格式备份

/**         * 备份联系人         */        public void backupContacts(Activity context, List<ContactInfo> infos) {            try {                String path = Environment.getExternalStorageDirectory() + "/contacts.vcf";                OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(path), "UTF-8");                VCardComposer composer = new VCardComposer();                for (ContactInfo info : infos) {                    ContactStruct contact = new ContactStruct();                    contact.name = info.getName();                    // 获取联系人电话信息, 添加至 ContactStruct                    List<PhoneInfo> numberList = info                            .getPhoneList();                    for (ContactInfo.PhoneInfo phoneInfo : numberList) {                        contact.addPhone(phoneInfo.type, phoneInfo.number,                                null, true);                    }                    // 获取联系人Email信息, 添加至 ContactStruct                    List<EmailInfo> emailList = info.getEmail();                    for (ContactInfo.EmailInfo emailInfo : emailList) {                        contact.addContactmethod(Contacts.KIND_EMAIL,                                emailInfo.type, emailInfo.email, null, true);                    }                    String vcardString = composer.createVCard(contact,                            VCardComposer.VERSION_VCARD30_INT);                    writer.write(vcardString);                    writer.write("\n");                    writer.flush();                }                writer.close();            } catch (UnsupportedEncodingException e) {                e.printStackTrace();            } catch (FileNotFoundException e) {                e.printStackTrace();            } catch (VCardException e) {                e.printStackTrace();            } catch (IOException e) {                e.printStackTrace();            }        }

获取VCard文件中的联系人信息

/**         * 获取vCard文件中的联系人信息         *         * @return List<ContactInfo>         */        public List<ContactInfo> restoreContacts() throws Exception {            List<ContactInfo> contactInfoList = new ArrayList<ContactInfo>();            VCardParser parse = new VCardParser();            VDataBuilder builder = new VDataBuilder();            String file = Environment.getExternalStorageDirectory() + "/contacts2.vcf";            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));            String vcardString = "";            String line;            while ((line = reader.readLine()) != null) {                vcardString += line + "\n";            }            reader.close();            boolean parsed = parse.parse(vcardString, "UTF-8", builder);            if (!parsed) {                throw new VCardException("Could not parse vCard file: " + file);            }            List<VNode> pimContacts = builder.vNodeList;            for (VNode contact : pimContacts) {                ContactStruct contactStruct = ContactStruct.constructContactFromVNode(contact, 1);                // 获取备份文件中的联系人电话信息                List<ContactStruct.PhoneData> phoneDataList = contactStruct.phoneList;                List<PhoneInfo> phoneInfoList = new ArrayList<PhoneInfo>();                for (ContactStruct.PhoneData phoneData : phoneDataList) {                    ContactInfo.PhoneInfo phoneInfo = new ContactInfo.PhoneInfo();                    phoneInfo.number = phoneData.data;                    phoneInfo.type = phoneData.type;                    phoneInfoList.add(phoneInfo);                }                // 获取备份文件中的联系人邮箱信息                List<ContactStruct.ContactMethod> emailList = contactStruct.contactmethodList;                List<EmailInfo> emailInfoList = new ArrayList<EmailInfo>();                // 存在 Email 信息                if (null != emailList) {                    for (ContactStruct.ContactMethod contactMethod : emailList) {                        if (Contacts.KIND_EMAIL == contactMethod.kind) {                            ContactInfo.EmailInfo emailInfo = new ContactInfo.EmailInfo();                            emailInfo.email = contactMethod.data;                            emailInfo.type = contactMethod.type;                            emailInfoList.add(emailInfo);                        }                    }                }                ContactInfo info = new ContactInfo(contactStruct.name).setPhoneList(phoneInfoList).setEmail(emailInfoList);                contactInfoList.add(info);            }            return contactInfoList;        }

将从VCard中获取的联系人数据插入到手机中

/**         * 向手机中录入联系人信息         *         * @param info 要录入的联系人信息         */        public void addContacts(Activity context, ContactInfo info) {            ContentValues values = new ContentValues();            //首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId            Uri rawContactUri = context.getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, values);            long rawContactId = ContentUris.parseId(rawContactUri);            //往data表入姓名数据            values.clear();            values.put(ContactsContract.RawContacts.Data.RAW_CONTACT_ID, rawContactId);            values.put(ContactsContract.RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);            values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, info.getName());            context.getContentResolver().insert(                    ContactsContract.Data.CONTENT_URI, values);            // 获取联系人电话信息            List<PhoneInfo> phoneList = info.getPhoneList();            /** 录入联系电话 */            for (ContactInfo.PhoneInfo phoneInfo : phoneList) {                values.clear();                values.put(ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId);                values.put(ContactsContract.RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);                // 设置录入联系人电话信息                values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneInfo.number);                values.put(ContactsContract.CommonDataKinds.Phone.TYPE, phoneInfo.type);                // 往data表入电话数据                context.getContentResolver().insert(                        ContactsContract.Data.CONTENT_URI, values);            }            // 获取联系人邮箱信息            List<EmailInfo> emailList = info.getEmail();            /** 录入联系人邮箱信息 */            for (ContactInfo.EmailInfo email : emailList) {                values.clear();                values.put(ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId);                values.put(ContactsContract.RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);                // 设置录入的邮箱信息                values.put(ContactsContract.CommonDataKinds.Email.DATA, email.email);                values.put(ContactsContract.CommonDataKinds.Email.TYPE, email.type);                // 往data表入Email数据                context.getContentResolver().insert(                        ContactsContract.Data.CONTENT_URI, values);            }        }    }

异步处理与功能使用DEMO

package com.pku.codingma.backupandrecovercontactdemo;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import com.dd.CircularProgressButton;import java.util.List;/** * A placeholder fragment containing a simple view. */public class BackupAndRecoverContactActivityFragment extends Fragment implements View.OnClickListener{    CircularProgressButton mBackupContactButton;    CircularProgressButton mRecoverContactButton;    //标记消息的来源    public final int BACKUP_WHAT = 0;    public final int RECOVER_WHAT = 1;    //标记成功还是失败    public final int SUCCESS_FLAG = 1;    public final int FAIL_FLAG = 0;    //用于进行备份和还原操作的ContactHandler内部类    ContactInfo.ContactHandler handler = ContactInfo.ContactHandler.getInstance();    public BackupAndRecoverContactActivityFragment() {    }    Handler mBackupAndRecoverProcessHandler = new Handler(){        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            if (msg.what == BACKUP_WHAT){                //add your action                if (msg.arg1 == SUCCESS_FLAG){                    mBackupContactButton.setProgress(100);                }else {                    mBackupContactButton.setProgress(-1);                }            }else if (msg.what == RECOVER_WHAT){                //add your action                if (msg.arg1 == SUCCESS_FLAG){                    mRecoverContactButton.setProgress(100);                }else {                    mRecoverContactButton.setProgress(-1);                }            }            ShowTipTool.showTip(getActivity(), msg.obj.toString());        }    };    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        View view =  inflater.inflate(R.layout.fragment_backup_and_recover_contact, container, false);        mBackupContactButton = (CircularProgressButton) view.findViewById(R.id.backup_contact_button);        mRecoverContactButton = (CircularProgressButton) view.findViewById(R.id.recover_contact_button);        initEvent();        return view;    }    private void initEvent() {        mRecoverContactButton.setOnClickListener(this);        mBackupContactButton.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()){            case R.id.backup_contact_button:                backup_contact();                break;            case R.id.recover_contact_button:                recover_contact();                break;            default:                break;        }    }    public void backup_contact(){        //让按钮进入工作状态        mBackupContactButton.setIndeterminateProgressMode(true);        mBackupContactButton.setProgress(50);        new Thread(new Runnable() {            @Override            public void run() {                //新建一条Handler处理的消息                Message message = new Message();                try{                    // 进行备份联系人信息动作                    handler.backupContacts(getActivity(), handler.getContactInfo(getActivity()));                    //如果顺利,则将消息的参数设置为成功                    message.obj = "backup success";                    message.arg1 = SUCCESS_FLAG;                }catch (Exception e){                    //如果出现异常,则将消息的参数设置为失败                    message.obj = "backup fail";                    message.arg1 = FAIL_FLAG;                    e.printStackTrace();                }finally {                    //最后设置消息来源并发送                    message.what = BACKUP_WHAT;                    mBackupAndRecoverProcessHandler.sendMessage(message);                }            }        }).start();    }    //与backup基本相同,不再注释    public void recover_contact(){        mRecoverContactButton.setIndeterminateProgressMode(true);        mRecoverContactButton.setProgress(50);        new Thread(new Runnable() {            @Override            public void run() {                Message message = new Message();                try {                    // 获取要恢复的联系人信息                    List<ContactInfo> infoList = handler.restoreContacts();                    for (ContactInfo contactInfo : infoList) {                        // 恢复联系人                        handler.addContacts(getActivity(), contactInfo);                    }                    message.obj = "recover success";                    message.arg1 = SUCCESS_FLAG;                } catch (Exception e) {                    message.obj = "recover fail";                    message.arg1 = FAIL_FLAG;                    e.printStackTrace();                }finally {                    message.what = RECOVER_WHAT;                    mBackupAndRecoverProcessHandler.sendMessage(message);                }            }        }).start();    }}

添加读写权限

<uses-permission android:name="android.permission.READ_CONTACTS"/><uses-permission android:name="android.permission.WRITE_CONTACTS"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

效果图若干张

依次为初始状态,处理状态,完成状态,异常出错状态
这里写图片描述

Demo完整代码请猛戳这里

文章原始来源与转载请标明的出处http://blog.csdn.net/u012145166/article/details/51052880

参考http://www.cnblogs.com/lw900320/archive/2013/01/10/2855145.html

  相关解决方案