Android开发之调用系统的ContentProvider——短信的备份和恢复

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dmk877/article/details/50518464
     转载请注明出处: http://blog.csdn.net/dmk877/article/details/50518464

     相关文章Android开发之内容提供者——创建自己的ContentProvider(详解)

   忍耐和坚持虽是痛苦的事情,但却能渐渐地为你带来好处.——奥维德。

   可能在坚持一件事情一段时间后,我们脑海中会有很多放弃的念头,可能在放弃之后的几年后,我们会想如果当时坚持下来会怎么怎么样。。。,但是可惜的是我们没有坚持。最近比较懒,也在这里提醒自己,不要迷失自己,坚持学习。

   在上一篇我们讲到了如何创建自己的ContentProvider,如果你掌握了上一篇所讲的内容,那么相信今天这一篇,你会很轻松的掌握。这一篇的主要内容就是调用谷歌工程师给我们提供好的ContentProvider,也就是说谷歌定义好一个ContentProvider后会给我们一个Uri,我们拿着这个Uri就可以得到相应的数据。如果你没调用过系统的Uri,没有关系,今天我们会通过一个案例来详细讲解怎么调用。废话不多说进入正题, 如有谬误欢迎批评指正,如有疑问欢迎留言。

   通过本篇博客你将学到以下知识点
   ①如何调用系统的ContentProvider
   ②如何通过谷歌给我们的Uri获得短信的数据
   ③一个案例将手机中的短信进行备份和恢复

1、如何调用系统的ContentProvider

    其实阅读了上一篇文章之后,这个问题会很好的理解,谷歌工程师在将ContentProvider写好之后,肯定会给我们一个Uri,只要知道这个Uri,我们就可以拿到我们需要的数据,比方说你想获得手机短信的信息,那么必定有和其对应的Uri,你想获得图库、联系人信息,也必定有相应的Uri与之对应。知道对应的Uri后,就可以过ContentResolver这个对象,根据Uri进行数据访问。更多的内容请参考: Android开发之内容提供者——创建自己的ContentProvider(详解)今天的主要任务就是完成一个案例获取系统的短信数据。

2、案例(手机短信数据的获取,以及备份和恢复)

    接下来我们就来看一个案例,这个案例的主要功能就是根据Uri获取手机短信的信息,并将其备份和恢复,它的效果图如下:

          这个图片演示了这样一种功能,首先在DDMS中向模拟器中发几条短信,然后运行我们的程序,点击备份,提示备份成功后,将所有的短信删除,然后在我们的程序中点击恢复,打开短信界面发现刚才删除的短信已经恢复,这就是我们要实现的功能

    首先来分析一下怎么实现上述效果,如果想备份短信,首先要做的就是获取短信的列表,这一步比较简单因为谷歌已经将其封装好,我们所要做的就是用Uri去查询短信库,就O了,然后拿到数据后需要将数据以XML的形式保存到SD卡里面,当然你用其它的方式也可以,只要能将其恢复就行。最后恢复的时候将指定路径的XML文件解析,根据Uri将解析的短信数据插入到系统的短信列表中。思路就是这样一个思路。没有看懂没关系,下面会有源码以及对它们的分析。

了解了大概思路后,另一个重要的任务就是看看短信的表结构在模拟器中它的路径是data->data->com.android.providers.telephony->databases下,如下图

将其导出然后用Sqlite数据打开可以看到数据的结构如下,这里只关心threads表和sms表就够了
threads表的结构如下

其中
_id:用于区分不同的电话号码,系统会为不同的电话号码分配不同的_id。
date:收到信息的时间(如果收到来自同一个phone number多条信息,并且有对于一条信息未读,那么date表示收到的最后一条信息时的时间)
message_count:收到的信息的数目
read: 0. 代表未读。 1.代表 已读
对于其它字段一般很少用到,这里就不多做介绍了,

sms表的结构如下

其中
_id:用于区分不同的短信

date: 该条短信接收的时间

read: 0表未读,1表已读

body:  表示具体的短信内容

到这里准备工作还差一步就可以进行代码的书写了,哪一步呢?就是访问这个数据库的Uri,对于访问手机短信的Uri主要有以下这么几个
content://sms/           所有短信
content://sms/inbox      收件箱
content://sms/sent       已发送
content://sms/draft      草稿
content://sms/outbox     发件箱
content://sms/failed     发送失败
content://sms/queued     待发送列表
           在这个案例中我们用content://sms/,因为是备份肯定是备份所有的短信,好了,下面一起来看看代码吧。首先要做的就是根据Uri获取短信的列表,这里新建一个SmsManage类,将备份和恢复的方法放到这个类中,获取短信列表的代码如下
     /**
      * 获取短信列表
      * @return
      */
      public List<SmsData> getSmsList() {
            //获取所有短信的 Uri
           Uri uri = Uri. parse( "content://sms/");
            //获取ContentResolver对象
           ContentResolver contentResolver = mContext.getContentResolver();
            //根据Uri 查询短信数据
           Cursor cursor = contentResolver.query(uri, null, null, null, null);
            if ( null != cursor) {
                Log. i( TAG, "cursor.getCount():" + cursor.getCount());
                 //根据得到的Cursor一条一条的添加到smsList(短信列表)中
                 while (cursor.moveToNext()) {
                      int _id = cursor.getInt(cursor.getColumnIndex("_id" ));
                      int type = cursor.getInt(cursor.getColumnIndex("type" ));
                     String address = cursor.getString(cursor.getColumnIndex( "address"));
                     String body = cursor.getString(cursor.getColumnIndex("body" ));
                     String date = cursor.getString(cursor.getColumnIndex("date" ));
                     SmsData smsData = new SmsData(_id, type, address, body, date);
                      smsList.add(smsData);
                }
                cursor.close();
           }
            return smsList;
     }
           可以看到上述代码就是根据 content://sms/这个Uri去查询手机中短信的数据库,得到一个Cursor这个Cursor就包含了一条一条的短信。然后去遍历这个Cursor将我们需要的数据添加到smsList中。这样短信数据就拿到了,因为我们做的功能是短信备份,所以接下来需要将smsList这个集合中的数据保存到本地,以方便短信恢复的时候去读取保存的这个文件,那么问题来了,怎样将smsList这个集合以文件的形式保存到本地呢?当然方法有很多,这里我们采用的是使用XmlSerializer将其序列化,待我们需要恢复的时候使用XmlPullParser  将其反序列化,就可以拿到备份的数据,听起来感觉挺高大上的,其实很简单就是对xml的操作。下面来看看序列化的代码即将上面得到的集合smsList中的数据生成一个xml文件,并保存到本地,代码如下
/**
 * 将短信数据保存到 sd卡中
 */
public void saveSmsToSdCard(){
            smsList=getSmsList();
            //获得一个序列化对象
           XmlSerializer xmlSerializer=Xml. newSerializer();
            //将生成的 xml文件保存到sd 卡中名字为"sms.xml"
           File file= new File(Environment.getExternalStorageDirectory(), "sms.xml");
           FileOutputStream fos;
           
            try {
                fos = new FileOutputStream(file);
                xmlSerializer.setOutput(fos, "utf-8");
                xmlSerializer.startDocument( "utf-8", true);
                xmlSerializer.startTag( null, "smss");
                
                xmlSerializer.startTag( null, "count");
                xmlSerializer.text( smsList.size()+ "");
                xmlSerializer.endTag( null, "count");
                
                 for(SmsData smsData: smsList){
                     
                     xmlSerializer.startTag( null, "sms");
                     
                     xmlSerializer.startTag( null, "_id");
                     xmlSerializer.text(smsData.get_id()+ "");
                     System. out.println( "smsData.get_id()=" +smsData.get_id());
                     xmlSerializer.endTag( null, "_id");
                     
                     xmlSerializer.startTag( null, "type");
                     xmlSerializer.text(smsData.getType()+ "");
                     System. out.println( "smsData.getType=" +smsData.getType());
                     xmlSerializer.endTag( null, "type");
                     
                     xmlSerializer.startTag( null, "address");
                     xmlSerializer.text(smsData.getAddress()+ "");
                     System. out.println( "smsData.getAddress()=" +smsData.getAddress());
                     xmlSerializer.endTag( null, "address");
                     
                     xmlSerializer.startTag( null, "body");
                     xmlSerializer.text(smsData.getBody()+ "");
                     System. out.println( "smsData.getBody()=" +smsData.getBody());
                     xmlSerializer.endTag( null, "body");
                     
                     xmlSerializer.startTag( null, "date");
                     xmlSerializer.text(smsData.getDate()+ "");
                     System. out.println( "smsData.getDate()=" +smsData.getDate());
                     xmlSerializer.endTag( null, "date");
                     
                     xmlSerializer.endTag( null, "sms");
                }
                xmlSerializer.endTag( null, "smss");
                xmlSerializer.endDocument();
                
                fos.flush();
                fos.close();
                Toast. makeText( mContext, "备份完成", Toast.LENGTH_SHORT ).show();
           } catch (FileNotFoundException e) {
                e.printStackTrace();
           } catch (IllegalArgumentException e) {
                e.printStackTrace();
           } catch (IllegalStateException e) {
                e.printStackTrace();
           } catch (IOException e) {
                e.printStackTrace();
           }
     
     }
通过调用以上方法就将短信以xml的形式保存到了本地。运行这个方法后可以再sd卡中看到sms.xml文件,将其导出来可以看到它的格式如下

注:实际上xml文件中它是一行这里为了让大家更清楚的看清结构,我手动将其改成上述格式了。
保存到本地后,工作就剩下最后一步了,那就是将这个xml文件反序列化,并将其中的数据一条一条插入到短信的数据库中,与其对应的代码如下
     /**
      * 将指定路径的 xml文件中的数据插入到短信数据库中
      * @param path
      */
      public void restoreSms(String path) {
           File file = new File(path);
            //得到一个解析 xml的对象
           XmlPullParser parser = Xml. newPullParser();
            try {
                 fis = new FileInputStream(file);
                parser.setInput( fis, "utf-8");
                ContentValues values = null;
                 int type = parser.getEventType();
                 while (type != XmlPullParser. END_DOCUMENT) {
                      switch (type) {
                      case XmlPullParser. START_TAG:
                            if ( "count".equals(parser.getName())) {
                           } else if ("sms" .equals(parser.getName())) {
                                values = new ContentValues();
                           } else if ("type" .equals(parser.getName())) {
                                values.put( "type", parser.nextText());
                           } else if ("address" .equals(parser.getName())) {
                                values.put( "address", parser.nextText());
                           } else if ("body" .equals(parser.getName())) {
                                values.put( "body", parser.nextText());
                           } else if ("date" .equals(parser.getName())) {
                                values.put( "date", parser.nextText());
                           }
                            break;
                      case XmlPullParser. END_TAG:
                            if ( "sms".equals(parser.getName())) {// 如果节点是 sms
                                Uri uri = Uri.parse( "content://sms/");
                                ContentResolver resolver = mContext.getContentResolver();
                                resolver.insert(uri, values);//向数据库中插入数据
                                System. out.println( "插入成功" );
                                values = null; //
                           }
                            break;
                     }
                     type=parser.next();
                }
           } catch (FileNotFoundException e) {
                e.printStackTrace();
           } catch (XmlPullParserException e) {
                e.printStackTrace();
           } catch (NumberFormatException e) {
                e.printStackTrace();
           } catch (IOException e) {
                e.printStackTrace();
           }
     }
可以看到在上述方法中判断xml的END_TAG是不是"sms"如果是的话说明一条短信的"type"、"address"、"body"、"date"这些信息已经拿到,然后就根据Uri将这条数据插入到数据库中,就完成一条短信的恢复,待读到 END_DOCUMENT说明xml文件已经读完,此时所备份的短信就全部恢复了。

好了今天这篇文章就到这里了, 如果发现文章中的错误,欢迎指出,如果有疑问请留言, 谢谢。如果你觉的本篇文章对你有帮助,就赞一下,顶一个呗,谢谢您的支持。





猜你喜欢

转载自blog.csdn.net/dmk877/article/details/50518464
今日推荐