Android基础——02数据存储和界面展现

测试介绍

好的软件不是写出来, 测出来的.

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();
        }


    }



}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值