测试介绍
好的软件不是写出来, 测出来的.
1、根据测试的时候 是否有源代码:
白盒测试: 写测试代码 测试源代码里面的业务方法
黑盒测试: 不知道源代码, 测试应用程序的业务逻辑.
2、根据测试的粒度
方法测试 function test
单元测试 unit test junit测试框架
集成测试 integration test
系统测试 system test
3、根据测试的暴力程度
冒烟测试 smoke test
压力测试 pressure test
android中的压力测试:
–>adb shell
–>monkey 5000
单元测试
【1】定义一个类继承AndroidTestCase
【2】在清单文件配置uses-library和instrumentation
在没有笔记的情况下,该怎么配置清单信息呢?
自己手动创建一个Android的测试工程,在测试工程里面会自动配置好
单元测试的步骤是:
先创建一个类,里面有个计算和的方法
package com.itheima.unit;
public class Calc {
/**
* 定义一个计算器相机的方法
*/
public int add(int x,int y){
return x + y;
}
}
然后再定义一个类,继承AndroidTestCase,里面写上要测试的方法和数据,并写明断言,如果断言正确,则说明单元测试显示正确结果,否则显示错误结果
package com.itheima.unit;
import android.test.AndroidTestCase;
public class CalcTest extends AndroidTestCase {
//写测试方法
public void testAdd(){
Calc calc = new Calc();
int result = calc.add(5, 3);
//断言
assertEquals(8, result);
}
}
在清单文件中这样配置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.itheima.unit"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<!--配置要测试的包名-->
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.itheima.unit" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<!-- 配置函数库 -->
<uses-library android:name="android.test.runner" />
<activity
android:name="com.itheima.unit.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
出此案绿色的条就说明单元测试成功了
日志猫的使用
通常通过打Log的方式,日志信息会打印在日志猫上,以此来查看程序的错误
package com.itheima.logcat;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
public class MainActivity extends Activity {
private static final String tag = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v(tag, "我是v级别");
Log.i(tag, "我是info级别");
Log.d(tag, "我是debug级别");
Log.w(tag, "我是warn级别");
Log.e(tag, "我是error级别");
System.out.println("哈哈哈哈");
}
}
verbose是黑色的
debug是蓝色的
info是绿色的
warn是黄色的
error是红色的
system.out是绿色的
Login登陆案例
【1】画UI
实现以上UI的代码是:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<EditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入用户名" />
<EditText
android:id="@+id/et_userpassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:password="true"
android:hint="请输入密码" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
>
<CheckBox
android:id="@+id/cb_ischeck"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="记住用户名密码" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="login"
android:layout_alignParentRight="true"
android:text="登录" />
</RelativeLayout>
</LinearLayout>
【2】写业务逻辑:
想要实现的需求是在写上用户名密码之后,当勾选记住用户名密码的时候,点击登录,就会把用户输入的用户名密码写入到手机的内存中,
而且在下一次启动的时候,会先读取内存中的用户的信息,然后将内存中的信息显示到屏幕上
package com.itheima.login;
import java.util.Map;
import android.os.Bundle;
import android.app.Activity;
import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private EditText et_name;
private EditText et_userpassword;
private CheckBox cb_ischeck;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//[1]找到我们关心的控件
et_name = (EditText) findViewById(R.id.et_username);
et_userpassword = (EditText) findViewById(R.id.et_userpassword);
cb_ischeck = (CheckBox) findViewById(R.id.cb_ischeck);
//[1.1]读取 data/data 下 info.txt信息
Map<String, String> maps = UserInfoUtils.readInfo();
if (maps!=null) {
//把name 和 pwd 取出来
String name = maps.get("name");
String pwd = maps.get("pwd");
//[1.2]把name 和pwd 显示到editText控件上
et_name.setText(name);
et_userpassword.setText(pwd);
}
}
//[2]写按钮的点击事件
public void login(View v){
//[2.1]获取用户名和密码
String name = et_name.getText().toString().trim();
String pwd = et_userpassword.getText().toString().trim();
//[2.2]判断name 和 pwd 是否为空
if (TextUtils.isEmpty(name)||TextUtils.isEmpty(pwd)) {
Toast.makeText(MainActivity.this, "用户名或密码不能为空", 1).show();
}else {
//[2.3]进行登录的逻辑
System.out.println("连接服务器 进行登录 等我们讲到 第四天 网络 编程 在说");
if (cb_ischeck.isChecked()) {
//[2.4]把用户名和密码的数据给我存起来
boolean result = UserInfoUtils.saveInfo(name, pwd);
if (result) {
Toast.makeText(MainActivity.this, "保存成功", 1).show();
}else{
Toast.makeText(MainActivity.this, "保存失败", 1).show();
}
}else {
Toast.makeText(MainActivity.this, "请勾选cb", 1).show();
}
}
}
}
中间需要有一个把用户名和密码写入到内存中的操作,我们单独给他封装成一个工具类,然后直接使用工具类的方法来进行写入操作,代码如下:
package com.itheima.login;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import android.content.Context;
public class UserInfoUtils {
// 保存用户名和密码的业务方法
public static boolean saveInfo(String username, String pwd) {
try {
String result = username + "##" + pwd;
// [1]创建file类指定我们要把数据存储的位置
File file = new File("/data/data/com.itheima.login/info.txt");
// [2]创建一个文件输出流
FileOutputStream fos = new FileOutputStream(file);
fos.write(result.getBytes());
fos.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
// 读取用户的信息
public static Map<String, String> readInfo() {
// [1]定义map
try {
Map<String, String> maps = new HashMap<String, String>();
File file = new File("/data/data/com.itheima.login/info.txt");
FileInputStream fis = new FileInputStream(file);
BufferedReader bufr = new BufferedReader(new InputStreamReader(fis));
String content = bufr.readLine(); // 读取数据
// 切割字符串 封装到map集合中
String[] splits = content.split("##");
String name = splits[0];
String pwd = splits[1];
// 把name 和 pwd 放入map中
maps.put("name", name);
maps.put("pwd", pwd);
fis.close();
return maps;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
使用上下文获取到文件目录
在上边的例子中如果写一个要保存的文件的路径会非常的麻烦,
/data/data/com.itheima.login/info.txt
如果使用上下文的话就会非常的省事
context.getFileDir.getPath();
这样就获取到了本工程所在的目录/data/data/com.itheima.login,还会在包下自己创建一个文件夹/data/data/com.itheima.login/files,比硬编码方便的多。
使用上下文还可以直接获取到本工程的输出流,
上边的例子用上下文获取到输出流的方式来进行实现的话,就会很方便:
package com.itheima.login;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import android.content.Context;
public class UserInfoUtils {
// 保存用户名和密码的业务方法
public static boolean saveInfo(Context context,String username, String pwd) {
try {
String result = username + "##" + pwd;
// [3]通过上下文获取FileOutputStream
FileOutputStream fos = context.openFileOutput("infoo.txt", 0);
fos.write(result.getBytes());
fos.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
// 读取用户的信息
public static Map<String, String> readInfo(Context context) {
// [1]定义map
try {
Map<String, String> maps = new HashMap<String, String>();
FileInputStream fis = context.openFileInput("infoo.txt");
BufferedReader bufr = new BufferedReader(new InputStreamReader(fis));
String content = bufr.readLine(); // 读取数据
// 切割字符串 封装到map集合中
String[] splits = content.split("##");
String name = splits[0];
String pwd = splits[1];
// 把name 和 pwd 放入map中
maps.put("name", name);
maps.put("pwd", pwd);
fis.close();
return maps;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
把数据保存到sd卡中
【1】第一种方法:就是直接把路径写死了,
“/mnt/sdcard/info.txt”
这里需要注意的是往sd卡中写数据的时候,需要先给用户一个权限,
这样才能把数据写入到sd卡上
【2】第二种方法:使用Environment对象获取到sd卡的目录:
使用这样的一个类不仅可以直接拿到sd卡的目录,还可以获取到sd卡的状态(是挂载的还是卸载的)使代码更具有健壮性
代码如下:
package com.itheima.login;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import android.os.Environment;
public class UserInfoUtils {
// 保存用户名和密码的业务方法
public static boolean saveInfo(String username, String pwd) {
try {
String result = username + "##" + pwd;
// [1]创建file类指定我们要把数据存储的位置 把数据保存到sd卡
String sdPath = Environment.getExternalStorageDirectory().getPath();
File file = new File(sdPath,"haha.txt");
// [2]创建一个文件输出流
FileOutputStream fos = new FileOutputStream(file);
fos.write(result.getBytes());
fos.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
// 读取用户的信息
public static Map<String, String> readInfo() {
// [1]定义map
try {
Map<String, String> maps = new HashMap<String, String>();
String sdPath = Environment.getExternalStorageDirectory().getPath();
File file = new File(sdPath,"haha.txt");
FileInputStream fis = new FileInputStream(file);
BufferedReader bufr = new BufferedReader(new InputStreamReader(fis));
String content = bufr.readLine(); // 读取数据
// 切割字符串 封装到map集合中
String[] splits = content.split("##");
String name = splits[0];
String pwd = splits[1];
// 把name 和 pwd 放入map中
maps.put("name", name);
maps.put("pwd", pwd);
fis.close();
return maps;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
获取sd卡的可用空间
先要将sd卡获取到的目录封装成一个file对象,然后file对象里面有获取最大值和可用值的方法,返回的是是个long类型的单位为字节的大小
然后使格式化的类Formatter里面的formatFileSize方法来讲byte单位的大小转换为正常格式的字符串,
将获取到的正常格式的sd卡的大小显示在手机屏幕上
代码如下:
package com.itheima.getsdcarddata;
import java.io.File;
import android.os.Bundle;
import android.os.Environment;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.text.format.Formatter;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity {
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//[1]找到我们关心的控件
TextView tv_total_size = (TextView) findViewById(R.id.textView1);
TextView tv_useable_size = (TextView) findViewById(R.id.textView2);
//[2]获取sd卡总大小 和可用空间
File file = Environment.getExternalStorageDirectory();
long totalSpace = file.getTotalSpace(); //总大小
long usableSpace = file.getUsableSpace(); //可用空间
//[3]转换数据格式
String formatToatalSpace = Formatter.formatFileSize(this, totalSpace);
String formatusableSpace = Formatter.formatFileSize(this,usableSpace);
//[4]展示到textview上
tv_total_size.setText("总大小:"+formatToatalSpace);
tv_useable_size.setText("可用的:"+formatusableSpace);
}
}
文件权限的介绍
文件的权限有四种:
私有:private
可追加的:append
可读的:read
可写的write
创建四种权限模式的文件
先创建四个按钮,按钮上绑定事件生成各自对应的文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click1"
android:text="private" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click2"
android:text="append" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click3"
android:text="read" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click4"
android:text="write" />
</LinearLayout>
开始写生成文件的业务逻辑:
package com.itheima.pri;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//点击按钮 生成一个私有的文件
public void click1(View v){
try {
FileOutputStream fos = openFileOutput("private.txt", MODE_PRIVATE);
// fos.write("private".getBytes());
fos.write("haha".getBytes());
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//点击按钮 使用MODE_APPEND模式 生成一个append.txt文件
public void click2(View v){
try {
FileOutputStream fos = openFileOutput("append.txt", MODE_APPEND);
// fos.write("append".getBytes());
fos.write("hehe".getBytes());
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//点击按钮 使用MODE_WORLD_READABLE 模式 生成一个read.txt 文件
public void click3(View v){
try {
FileOutputStream fos = openFileOutput("read.txt", MODE_WORLD_READABLE);
fos.write("read".getBytes());
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//点击按钮 使用这个模式MODE_WORLD_WRITEABLE 生成一个write.txt文件
public void click4(View v){
try {
FileOutputStream fos = openFileOutput("write.txt", MODE_WORLD_WRITEABLE);
fos.write("write".getBytes());
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
生成的文件如下图所示:
解释一下后边的rw-的意思:只用一张图来说
想要使用读取到之前创建好的文件的内容呢?
新创建一个工程,创建读取流,读取目标文件下的文件:
package com.itheima.readfile;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
File file = new File("/data/data/com.itheima.pri/files/write.txt");
FileInputStream fis = new FileInputStream(file);
BufferedReader bufr = new BufferedReader(new InputStreamReader(fis));
String content = bufr.readLine();
System.out.println("content:"+content);
} catch (Exception e) {
e.printStackTrace();
}
}
}
这里记住,只有可读权限的文件可以被读取到,其他类型的文件因为权限不够,所以读取不到。
修改已经存在的文件的权限:
进入到文件所在的目录:
找到对应的包找到对应的文件夹:
开始修改文件的权限:
这样文件权限就修改成功了,777表示三个阶段的文件权限都给了所有的权限,有权限就用1表示,没权限就用0表示,以此来算下的二进制码来表示的
SharedPreference介绍
在之前的存储用户信息的过程中,一直使用的是流来进行操作的,在Android中完全可以不用流来进行操作,就是使用SharedPreference来操作:
步骤是:根据上下文获取到SharedPreference对象,然后使用sp调用edit方法获取到Editor对象,使用Editer对象进行put操作,最后进行commit提交数据。
在获取数据的时候同样是得到sp对象,然后直接调用get方法获取到数据
代码示例:
package com.itheima.login;
import java.util.Map;
import android.os.Bundle;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
import com.itheima.sptest.R;
public class MainActivity extends Activity {
private EditText et_name;
private EditText et_userpassword;
private CheckBox cb_ischeck;
private SharedPreferences sp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//[0] 先初始化 sp 的实例
/**
* name 会帮助我们生成一个xml文件
* mode 模式
*/
sp = getSharedPreferences("config", 0);
//[1]找到我们关心的控件
et_name = (EditText) findViewById(R.id.et_username);
et_userpassword = (EditText) findViewById(R.id.et_userpassword);
cb_ischeck = (CheckBox) findViewById(R.id.cb_ischeck);
//[2]在 config.xml文件中把我们关心的数据取出来 然后显示到edittext控件上
String name = sp.getString("name", "");
String pwd = sp.getString("pwd", "");
//[3]把name 和 pwd 设置到edittext上
et_name.setText(name);
et_userpassword.setText(pwd);
//TODO 把checkbox状态逻辑给我写好
}
//[2]写按钮的点击事件
public void login(View v){
//[2.1]获取用户名和密码
String name = et_name.getText().toString().trim();
String pwd = et_userpassword.getText().toString().trim();
//[2.2]判断name 和 pwd 是否为空
if (TextUtils.isEmpty(name)||TextUtils.isEmpty(pwd)) {
Toast.makeText(MainActivity.this, "用户名或密码不能为空", 1).show();
}else {
//[2.3]进行登录的逻辑
System.out.println("连接服务器 进行登录 等我们讲到 第四天 网络 编程 在说");
if (cb_ischeck.isChecked()) {
//2.4 使用SharedPreferences 去保存数据 拿到sp的实例
//[2.5]获取sp的编辑器
Editor edit = sp.edit();
edit.putString("name", name);
edit.putString("pwd", pwd);
//[2.6]记得把edit 进行提交
edit.commit();
}else {
Toast.makeText(MainActivity.this, "请勾选cb", 1).show();
}
}
}
}
生成xml文件的第一种方式
就是传统的方式:通过sb组拼字符串的方式慢慢的写成一个xml文件的格式
将数据封装成对象,存进集合当中,在组拼字符串的时候直接遍历集合取出对象,然后取出对象里面的数据就好了
代码示例
先来一个数据封装成的对象:
package com.itheima.generatexml;
public class Sms {
private String address;
private String body;
private String date;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
开始组拼xml文档的字符串:
package com.itheima.generatexml;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
private List<Sms> smsLists;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//[1]初始化我们要备份的数据
smsLists = new ArrayList<Sms>();
for (int i = 0; i < 10; i++) {
Sms sms =new Sms();
sms.setAddress("10008"+i);
sms.setBody("nihao"+i);
sms.setDate("201"+i);
//[2]把sms对象加入到 集合中
smsLists.add(sms);
}
}
//点击按钮 通过StringBuffer 的方式生成一个xml文件
public void click(View v){
//[1]创建sb对象
StringBuffer sb = new StringBuffer();
//[2]开始组拼xml文件头
sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
//[3]开始组拼xml根节点
sb.append("<smss>");
//[4]开始组拼sms节点
for (Sms sms : smsLists) {
sb.append("<sms>");
//[5]开始组拼address节点
sb.append("<address>");
sb.append(sms.getAddress());
sb.append("</address>");
//[6]开始组拼body节点
sb.append("<body>");
sb.append(sms.getBody());
sb.append("</body>");
//[7]开始组拼date节点
sb.append("<date>");
sb.append(sms.getDate());
sb.append("</date>");
sb.append("</sms>");
}
sb.append("</smss>");
//[8]把数据保存到sd卡中
try {
File file = new File(Environment.getExternalStorageDirectory().getPath(),"smsbackup.xml");
FileOutputStream fos = new FileOutputStream(file);
fos.write(sb.toString().getBytes());
fos.close();//关闭流
} catch (Exception e) {
e.printStackTrace();
}
}
}
最后记住,因为在代码中要将数据写入到sd卡中,所以需要给一个权限:
这样一个xml文件就形成了。
生成xml文件的第二种方式
使用XmlSerializer类里面的方法进行操作
首先获取XmlSerializer对象,使用Xml.newSerializer()方法生成对象
设置序列化参数:setOutput()
设置文档开头startDocument()
设置开始标签startTag();
设置结束节点endTag();
设置节点中的文字text();
结束文档endDocument();
代码示例:
数据还是那个数据,集合还是那个集合
package com.itheima.generatexml;
public class Sms {
private String address;
private String body;
private String date;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
开始生成xml文件
package com.itheima.generatexml;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlSerializer;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.util.Xml;
import android.view.Menu;
import android.view.View;
import com.itheima.generatexml2.R;
public class MainActivity extends Activity {
private List<Sms> smsLists;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//[1]初始化我们要备份的数据
smsLists = new ArrayList<Sms>();
for (int i = 0; i < 10; i++) {
Sms sms =new Sms();
sms.setAddress("10008"+i);
sms.setBody("nihao"+i);
sms.setDate("201"+i);
//[2]把sms对象加入到 集合中
smsLists.add(sms);
}
}
//点击按钮 通过的XmlSerializer方式生成一个xml文件
public void click(View v){
try {
//[1]获取XmlSerializer 类的实例 通过Xml这个工具类去获取
XmlSerializer serializer = Xml.newSerializer();
//[2]设置 xmlserializer序列化器参数
File file = new File(Environment.getExternalStorageDirectory().getPath(),"smsbackup2.xml");
FileOutputStream fos = new FileOutputStream(file);
serializer.setOutput(fos, "utf-8");
//[3]开始写xml文档开头
serializer.startDocument("utf-8", true);
//[4]写 xml的根节点 namespace 命名空间
serializer.startTag(null, "smss");
//[5]循环写 sms节点
for (Sms sms : smsLists) {
serializer.startTag(null, "sms");
// [6]开始address节点
serializer.startTag(null, "address");
serializer.text(sms.getAddress());
serializer.endTag(null,"address");
// [7]开始body节点
serializer.startTag(null, "body");
serializer.text(sms.getBody());
serializer.endTag(null,"body");
// [8]开始date节点
serializer.startTag(null, "date");
serializer.text(sms.getDate());
serializer.endTag(null,"date");
//sms节点结束
serializer.endTag(null, "sms");
}
serializer.endTag(null, "smss");
//写文档结尾
serializer.endDocument();
fos.close();//关闭流
} catch (Exception e) {
e.printStackTrace();
}
}
}
因为数据是写入到sd卡中的,所以要在清单文件中给一个权限
对xml文件进行解析
就是通过XmlPullParser工具类来进行解析的
这个类的来源也是通过Xml类获取到的
获取到parser对象之后,通过setInput方法来设置要读取的xml文件和要使用的编码方式
解析xml文件的时候是按照指针的方式一行一行的往下读取的,针对每一行都有自己对应的事件
获取这样的事件的方法就是getEventType
指针一行一行的往下走是要依赖一个next方法的。
然后开始通过判断获取到的事件对象(int值)来判断指针指到的节点是开始节点开始结束节点,还可以获取到所在节点的名称和内容,还有属性
详情见代码
获取资产目录里面的文件可以使用上下文对象,getAsses().open(“资产目录中的文件名”)返回的是一个流对象
代码:
想要将xml文件中的内容显示到一个textView中,画UI
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/tv_weather"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>
创建bean
package com.itheima.xmpparser;
public class Channel {
private String id;
private String city;
private String temp;
private String wind;
private String pm250;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getTemp() {
return temp;
}
public void setTemp(String temp) {
this.temp = temp;
}
public String getWind() {
return wind;
}
public void setWind(String wind) {
this.wind = wind;
}
public String getPm250() {
return pm250;
}
public void setPm250(String pm250) {
this.pm250 = pm250;
}
@Override
public String toString() {
return "Channel [id=" + id + ", city=" + city + ", temp=" + temp
+ ", wind=" + wind + ", pm250=" + pm250 + "]";
}
}
创建解析xml文件的工具类:
package com.itheima.xmpparser;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import android.util.Xml;
public class WeatherParser {
/**
* 服务器是以流的形式把数据返回的
* @return
*/
public static List<Channel> parserXml(InputStream in) throws Exception{
//[0]声明集合对象
List<Channel> weatherLists = null;
Channel channel = null;
//[1]获取XmlPullParser 解析的实例
XmlPullParser parser = Xml.newPullParser();
//[2]设置XmlPullParser 的参数
parser.setInput(in, "utf-8");
//[3]获取事件类型
int type = parser.getEventType();
while(type!= XmlPullParser.END_DOCUMENT){
switch (type) {
case XmlPullParser.START_TAG: //解析开始标签
//[4]具体判断一下 解析到是哪个开始标志
if ("weather".equals(parser.getName())) {
//[5]创建一个集合对象
weatherLists = new ArrayList<Channel>();
}else if("channel".equals(parser.getName())){
//[6]创建Channel对象
channel = new Channel();
//[7]获取id值
String id = parser.getAttributeValue(0);
channel.setId(id);
}else if("city".equals(parser.getName())){
//[8]获取city的数据
String city = parser.nextText();
channel.setCity(city);
}else if("temp".equals(parser.getName())){
//[8]获取city的数据
String temp = parser.nextText();
channel.setTemp(temp);
}else if("wind".equals(parser.getName())){
//[8]获取city的数据
String wind = parser.nextText();
channel.setWind(wind);
}else if("pm250".equals(parser.getName())){
//[8]获取city的数据
String pm250 = parser.nextText();
channel.setPm250(pm250);
}
break;
case XmlPullParser.END_TAG: //解析结束标志
//判断要解析的结束标签
if ("channel".equals(parser.getName())) {
//把javabean对象存到集合中
weatherLists.add(channel);
}
break;
}
//不停的向下解析
type = parser.next();
}
return weatherLists;
}
}
在主函数中解析xml文件
package com.itheima.xmpparser;
import java.io.InputStream;
import java.util.List;
import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
//[1]显示天气信息
TextView tv_weather = (TextView) findViewById(R.id.tv_weather);
//[1.1]获取资产的管理者 通过上下文
InputStream inputStream = getAssets().open("weather.xml");
//[2]调用我们定义的解析xml业务方法
List<Channel> weatherlists = WeatherParser.parserXml(inputStream);
StringBuffer sb = new StringBuffer();
for (Channel channel : weatherlists) {
sb.append(channel.toString());
}
//[3]把数据展示到textviwe上
tv_weather.setText(sb.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}