Android(java)学习笔记191:ContentProvider使用之利用ContentProvider备份和还原手机短信(掌握)
1. 通过阅读系统源码我们知道:
短信的内容提供者:
content://sms/ 系统短信的内容提供者的路径
2. 利用ContentProvider备份和还原手机短信:
(1)新建一个Android工程,命名为"短信备份助手",如下:
(2)我们先实现UI布局,activity_main.xml,如下:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" 6 tools:context="com.himi.smsbackup.MainActivity" > 7 8 <Button 9 android:onClick="smsBackup" 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content" 12 android:text="备份" /> 13 <Button 14 android:onClick="smsRestores" 15 android:layout_width="match_parent" 16 android:layout_height="wrap_content" 17 android:text="还原" /> 18 19 </LinearLayout>
布局效果如下:
(3)编写MainActivity,如下:
1 package com.himi.smsbackup; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileOutputStream; 6 7 import org.xmlpull.v1.XmlPullParser; 8 import org.xmlpull.v1.XmlSerializer; 9 10 import android.app.Activity; 11 import android.app.AlertDialog; 12 import android.app.AlertDialog.Builder; 13 import android.content.ContentResolver; 14 import android.content.ContentValues; 15 import android.content.DialogInterface; 16 import android.content.DialogInterface.OnClickListener; 17 import android.database.Cursor; 18 import android.net.Uri; 19 import android.os.Bundle; 20 import android.os.Environment; 21 import android.util.Xml; 22 import android.view.View; 23 import android.widget.Toast; 24 25 public class MainActivity extends Activity { 26 27 @Override 28 protected void onCreate(Bundle savedInstanceState) { 29 super.onCreate(savedInstanceState); 30 setContentView(R.layout.activity_main); 31 } 32 33 34 /** 35 * 短信备份 36 * @param view 37 */ 38 public void smsBackup(View view) { 39 try { 40 // 系统短信数据库是私有的,不能访问,只能使用内容提供者ContentProvider去访问 41 ContentResolver resolver = getContentResolver(); 42 // 指定Uri 43 Uri uri = Uri.parse("content://sms/"); 44 Cursor cursor = resolver.query(uri, new String[] { "address", 45 "date", "type", "body" }, null, null, null); 46 // 存储为xml文件,跨平台 47 // 获取一个xml的序列化器serializer 48 XmlSerializer serializer = Xml.newSerializer(); 49 // 初始化设置xml序列化器serializer 50 File file = new File(Environment.getExternalStorageDirectory(), 51 "backup.xml"); 52 FileOutputStream os = new FileOutputStream(file); 53 serializer.setOutput(os, "utf-8"); 54 55 // 写xml文件的头 56 serializer.startDocument("utf-8", true); 57 serializer.startTag(null, "root"); 58 while (cursor.moveToNext()) { 59 serializer.startTag(null, "sms"); 60 61 serializer.startTag(null, "address"); 62 String address = cursor.getString(0); 63 serializer.text(address); 64 serializer.endTag(null, "address"); 65 66 serializer.startTag(null, "date"); 67 String date = cursor.getString(1); 68 serializer.text(date); 69 serializer.endTag(null, "date"); 70 71 serializer.startTag(null, "type"); 72 String type = cursor.getString(2); 73 serializer.text(type); 74 serializer.endTag(null, "type"); 75 76 serializer.startTag(null, "body"); 77 String body = cursor.getString(3); 78 serializer.text(body); 79 serializer.endTag(null, "body"); 80 81 serializer.endTag(null, "sms"); 82 } 83 cursor.close(); 84 serializer.endTag(null, "root"); 85 serializer.endDocument(); 86 os.close(); 87 Toast.makeText(this, "备份成功", 0).show(); 88 } catch (Exception e) { 89 // TODO 自动生成的 catch 块 90 e.printStackTrace(); 91 Toast.makeText(this, "备份失败", 0).show(); 92 } 93 } 94 95 /** 96 * 还原用户的备份的短信数据 97 * 还原之前要提醒用户是否要覆盖旧的数据 98 * @param view 99 */ 100 public void smsRestores(View view) { 101 File file = new File(Environment.getExternalStorageDirectory(), 102 "backup.xml"); 103 //file.lastModified();获取文件上一次备份时间 104 AlertDialog.Builder builder = new Builder(this); 105 builder.setTitle("提醒"); 106 builder.setMessage("是否清除旧的短信?"); 107 builder.setPositiveButton("确实清除", new OnClickListener() { 108 109 public void onClick(DialogInterface dialog, int which) { 110 Uri uri = Uri.parse("content://sms/"); 111 getContentResolver().delete(uri, null, null); 112 restore(); 113 114 } 115 }); 116 builder.setNegativeButton("不清楚数据", new OnClickListener() { 117 118 public void onClick(DialogInterface dialog, int which) { 119 restore(); 120 121 } 122 }); 123 124 builder.show(); 125 } 126 127 public void restore() { 128 try { 129 130 File file = new File(Environment.getExternalStorageDirectory(), 131 "backup.xml"); 132 FileInputStream is = new FileInputStream(file); 133 //获取xml的pull解析器 134 XmlPullParser parser = Xml.newPullParser(); 135 //初始化设置xml的pull解析器 136 parser.setInput(is, "utf-8"); 137 int type = parser.getEventType(); 138 139 String address = null; 140 String date = null; 141 String smstype = null; 142 String body = null; 143 while(type != XmlPullParser.END_DOCUMENT) { 144 switch (type) { 145 case XmlPullParser.START_TAG: 146 //开始解析标签 147 if("address".equals(parser.getName())) { 148 address = parser.nextText(); 149 }else if ("date".equals(parser.getName())){ 150 date = parser.nextText(); 151 }else if ("type".equals(parser.getName())){ 152 smstype = parser.nextText(); 153 }else if ("body".equals(parser.getName())){ 154 body = parser.nextText(); 155 } 156 157 break; 158 159 case XmlPullParser.END_TAG: 160 if ("sms".equals(parser.getName())) { 161 // 结束解析标签,把短信的数据加入到系统短信应用数据库中 162 ContentResolver resolver = getContentResolver(); 163 Uri uri = Uri.parse("content://sms/"); 164 ContentValues values = new ContentValues(); 165 values.put("address", address); 166 values.put("date", date); 167 values.put("type", smstype); 168 values.put("body", body); 169 resolver.insert(uri, values); 170 } 171 break; 172 } 173 type = parser.next();//指向下一待解析的标签 174 } 175 Toast.makeText(this, "还原成功", 0).show(); 176 } catch (Exception e) { 177 // TODO 自动生成的 catch 块 178 e.printStackTrace(); 179 Toast.makeText(this, "还原失败", 0).show(); 180 } 181 182 } 183 }
上面使用到要存取数据到SD卡,要添加相应的权限。同时读取系统短信应用也需要相应的权限,AndroidMainfest.xml,如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.himi.smsbackup" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk 8 android:minSdkVersion="15" 9 android:targetSdkVersion="17" /> 10 <uses-permission android:name="android.permission.READ_SMS"/> 11 <uses-permission android:name="android.permission.WRITE_SMS"/> 12 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 13 14 <application 15 android:allowBackup="true" 16 android:icon="@drawable/ic_launcher" 17 android:label="@string/app_name" 18 android:theme="@style/AppTheme" > 19 <activity 20 android:name=".MainActivity" 21 android:label="@string/app_name" > 22 <intent-filter> 23 <action android:name="android.intent.action.MAIN" /> 24 25 <category android:name="android.intent.category.LAUNCHER" /> 26 </intent-filter> 27 </activity> 28 </application> 29 30 </manifest>
(4)布署程序到模拟器上,如下:
•我们先在模拟器上模拟发送和接收几条短信,如下:
•回到上面我们编写的应用程序中,点击"备份",提示备份成功,如下:
•查看Sd保存路径,如下图,导出这个backup.xml文件到桌面,然后使用IE打开这个backup.xml文件,如下:
•这个时候,我们去删除模拟器上的短信,如下:
•回到编写的应用程序中,点击"还原",如下:
•回到系统短信页面,看到: