zoukankan      html  css  js  c++  java
  • Android核心基础(二)

    1、对应用进行单元测试

    在实际开发中,开发android软件的过程需要不断地进行测试。而使用Junit测试框架,侧是正规Android开发的必用技术,在Junit中可以得到组件,可以模拟发送事件和检测程序处理的正确性。

    第一步:首先在AndroidManifest.xml中加入下面红色代码:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"

          package="cn.itcast.action“ android:versionCode="1“  android:versionName="1.0">

     <application android:icon="@drawable/icon" android:label="@string/app_name">

            <uses-library android:name="android.test.runner" />

            ....

     </application>

     <uses-sdk android:minSdkVersion="6" />

     <instrumentation android:name="android.test.InstrumentationTestRunner"

      android:targetPackage="cn.itcast.action" android:label="Tests for My App" />

    </manifest>

    上面targetPackage指定的包要和应用的package相同。

    第二步:编写单元测试代码(选择要测试的方法,右键点击“Run As--Android Junit Test” ):

    import android.test.AndroidTestCase;

    import android.util.Log;

    public class XMLTest extends AndroidTestCase {

     public void testSomething() throws Throwable {

    Assert.assertTrue(1 + 1 == 3);

     }

    }

    根据是否知道程序的源代码:

    白盒测试:  知道源代码,根据源代码进行测试.

    黑盒测试:  没有程序的源代码只是测试程序的功能.

    根据测试的粒度 (模块的大小

    单元测试 unit test

    方法测试 function test

    集成测试 intergration test 

    系统测试 system test

    根据测试的次数 暴力程度

    冒烟测试 smoke test 

    压力测试 pressure test

    日志的等级

    ERROR > WARN > INFO > DEBUG > VERBOSE

    2、数据存储与访问

    很多时候我们的软件需要对处理后的数据进行存储或再次访问。Android为数据存储提供了如下几种方式:

    1文件

    2SharedPreferences(参数)

    3SQLite数据库

    4内容提供者(Content provider

    5网络

    3使用文件进行数据存储

    首先给大家介绍使用文件如何对数据进行存储,Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过程与在J2SE环境中保存数据到文件中是一样的。

    public class FileActivity extends Activity {

        @Override public void onCreate(Bundle savedInstanceState) {

            ... 

             FileOutputStream outStream = this.openFileOutput("itcast.txt", Context.MODE_PRIVATE);

             outStream.write("传智播客".getBytes());

             outStream.close();   

        }

    }

    openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存在,Android 会自动创建它。创建的文件保存在/data/data/<package name>/files目录,如: /data/data/cn.itcast.action/files/itcast.txt ,通过点击Eclipse菜单“Window-Show View-Other”,在对话窗口中展开android文件夹,选择下面的File Explorer视图,然后在File Explorer视图中展开/data/data/<package name>/files目录就可以看到该文件。

    openFileOutput()方法的第二参数用于指定操作模式,有四种模式,分别为: Context.MODE_PRIVATE    =  0

    Context.MODE_APPEND    =  32768

    Context.MODE_WORLD_READABLE =  1

    Context.MODE_WORLD_WRITEABLE =  2

    Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPEND

    Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。

    Context.MODE_WORLD_READABLEContext.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。

    MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。

    如果希望文件被其他应用读和写,可以传入: 

    openFileOutput("itcast.txt", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);

    android有一套自己的安全模型,当应用程序(.apk)在安装时系统就会分配给他一个userid,当该应用要去访问其他资源比如文件的时候,就需要userid匹配。默认情况下,任何应用创建的文件,sharedpreferences,数据库都应该是私有的(位于/data/data/<package name>/files),其他程序无法访问。除非在创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE ,只有这样其他程序才能正确访问。

    4、读取文件内容

    如果要打开存放在/data/data/<package name>/files目录应用私有的文件,可以使用Activity提供openFileInput()方法。

    FileInputStream inStream = this.getContext().openFileInput("itcast.txt");

    Log.i("FileTest", readInStream(inStream));

    readInStream()的方法请看本页下面备注。

    或者直接使用文件的绝对路径:

    File file = new File("/data/data/cn.itcast.action/files/itcast.txt");

    FileInputStream inStream = new FileInputStream(file);

    Log.i("FileTest", readInStream(inStream));

    注意:上面文件路径中的“cn.itcast.action”为应用所在包,当你在编写代码时应替换为你自己应用使用的包。

    对于私有文件只能被创建该文件的应用访问,如果希望文件能被其他应用读和写,可以在创建文件时,指定Context.MODE_WORLD_READABLEContext.MODE_WORLD_WRITEABLE权限。

    Activity还提供了getCacheDir()getFilesDir()方法:

    getCacheDir()方法用于获取/data/data/<package name>/cache目录

    getFilesDir()方法用于获取/data/data/<package name>/files目录

    public static String readInStream(FileInputStream inStream){

    try {

    ByteArrayOutputStream outStream = new ByteArrayOutputStream();

    byte[] buffer = new byte[1024];

    int length = -1;

    while((length = inStream.read(buffer)) != -1 ){

    outStream.write(buffer, 0, length);

    }

    outStream.close();

    inStream.close();

    return outStream.toString();

    } catch (IOException e) {

    Log.i("FileTest", e.getMessage());

    }

    return null;

    }

    文件访问模式

    context.getFilesDir();   /data/data/当前应用程序包名/files

    context.getCacheDir();   /data/data/当前应用程序包名/cache

    安装一个apk后 系统拷贝这个apk /data/app/xx.apk

    context.getPackageCodePath()

    直接获取一个文件的输入流

    FileInputStream fis = context.openFileInput("info.txt");

    等价于

    File file = new File(context.getFilesDir(),"info.txt"); 

    FileInputStream fis = new FileInputStream(file);

    直接获取一个文件的输出流

    context.openFileOutput("info.txt", Context.MODE_PRIVATE); //文件是私有模式

    等价于

    File file = new File(context.getFilesDir(),"info.txt");  //在当前应用程序的目录下 创建一个files目录 里面有一个文件 info.txt

    FileOutputStream fos = new FileOutputStream(file);

    文件访问权限

    - rw- rw- --- 私有

    - rw- rw- r-- 可读

    - rw- rw- -w- 可写

    - rw- rw- rw- 可读可写

    android系统有一个特点 每个应用程序 都是一个单独的用户.

    一个应用程序创建的文件 默认模式是私有的模式,

    别的应用程序不可以访问 这个应用程序私有的数据.

    ctrl + H

    文件访问模式

    package com.itheima.login.service;

    import java.io.BufferedReader;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.InputStreamReader;

    import android.content.Context;

    /**

     * 登陆相关的服务

     * 

     * @author Administrator

     * 

     */

    public class LoginService {

    //上下文  其实提供了应用程序 的一个详细的环境信息.  包括 包名是什么 /data/data/目录在哪里.

    //we do chicken right

    /**

     * 保存用户信息到文件

     * 

     * @param username

     *            用户名

     * @param password

     *            密码

     */

    public static void saveUserInfoToFile(Context context,String username, String password, int mode)

    throws Exception {

    FileOutputStream fos = context.openFileOutput("info.txt", mode);

    fos.write((username + "##" + password).getBytes());

    fos.close();

    }

    /**

     * 读取用户的用户名和密码

     * @return // zhangsan##123456

     */

    public static String readUserInfoFromFile(Context context) throws Exception{

    File file = new File(context.getFilesDir(),"info.txt"); 

    FileInputStream fis = new FileInputStream(file);

    BufferedReader br = new BufferedReader(new InputStreamReader(fis));

    String line = br.readLine();

    fis.close();

    br.close();

    return line;

    }

    }

    package com.itheima.login;

    import com.itheima.login.service.LoginService;

    import android.os.Bundle;

    import android.app.Activity;

    import android.content.Context;

    import android.text.TextUtils;

    import android.view.Menu;

    import android.view.View;

    import android.widget.CheckBox;

    import android.widget.EditText;

    import android.widget.RadioGroup;

    import android.widget.Toast;

    /**

     * activity 实际上是上下文的一个子类

     * 

     * @author Administrator

     * 

     */

    public class MainActivity extends Activity {

    private EditText et_username;

    private EditText et_password;

    private CheckBox cb_remeber_pwd;

    private RadioGroup rg_mode;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    cb_remeber_pwd = (CheckBox) findViewById(R.id.cb_remeber_pwd);

    et_username = (EditText) findViewById(R.id.et_username);

    et_password = (EditText) findViewById(R.id.et_password);

    try {

    String result = LoginService.readUserInfoFromFile(this);

    String[] infos = result.split("##");

    et_username.setText(infos[0]);

    et_password.setText(infos[1]);

    } catch (Exception e) {

    e.printStackTrace();

    }

    rg_mode = (RadioGroup) findViewById(R.id.rg_mode);

    }

    /**

     * 登陆按钮的点击事件

     * 

     * @param view

     */

    public void login(View view){

    String username = et_username.getText().toString().trim();

    String password = et_password.getText().toString().trim();

    if(TextUtils.isEmpty(username)||TextUtils.isEmpty(password)){

    Toast.makeText(getApplicationContext(), "用户名或者密码不能为空", 0).show();

    return;

    }

    //检查是否勾选了cb

    if(cb_remeber_pwd.isChecked()){//记住密码

    try {

    int rb_id = rg_mode.getCheckedRadioButtonId();//获取哪个id被选中

    int mode = Context.MODE_PRIVATE;

    switch (rb_id) {

    case R.id.rb_private://私有

    mode = Context.MODE_PRIVATE;

    break;

    case R.id.rb_readable://可读

    mode = Context.MODE_WORLD_READABLE;

    break;

    case R.id.rb_writeable://可写

    mode = Context.MODE_WORLD_WRITEABLE;

    break;

    case R.id.rb_public://可读可写

    mode = Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE;

    break;

    }

    LoginService.saveUserInfoToFile(this, username, password,mode);

    Toast.makeText(this, "保存用户名密码成功", 0).show();

    } catch (Exception e) {

    e.printStackTrace();

    Toast.makeText(getApplicationContext(), "保存用户名密码失败", 0).show();

    }

    }

    }

    }

    登录案例

    package com.itheima.login.service;

    import java.io.BufferedReader;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.InputStreamReader;

    import android.content.Context;

    /**

     * 登陆相关的服务

     * 

     * @author Administrator

     * 

     */

    public class LoginService {

    //上下文  其实提供了应用程序 的一个详细的环境信息.  包括 包名是什么 /data/data/目录在哪里.

    //we do chicken right

    /**

     * 保存用户信息到文件

     * 

     * @param username

     *            用户名

     * @param password

     *            密码

     */

    public static void saveUserInfoToFile(Context context,String username, String password)

    throws Exception {

    //File file = new File("/data/data/com.itheima.login/info.txt");

    // File file = new File(context.getFilesDir(),"info.txt");  //在当前应用程序的目录下 创建一个files目录 里面有一个文件 info.txt

    // FileOutputStream fos = new FileOutputStream(file);

    FileOutputStream fos = context.openFileOutput("info.txt", Context.MODE_PRIVATE);//追加模式

    // zhangsan##123456

    fos.write((username + "##" + password).getBytes());

    fos.close();

    }

    /**

     * 读取用户的用户名和密码

     * @return // zhangsan##123456

     */

    public static String readUserInfoFromFile(Context context) throws Exception{

    File file = new File(context.getFilesDir(),"info.txt"); 

    FileInputStream fis = new FileInputStream(file);

    BufferedReader br = new BufferedReader(new InputStreamReader(fis));

    String line = br.readLine();

    fis.close();

    br.close();

    return line;

    }

    }

    package com.itheima.login;

    import com.itheima.login.service.LoginService;

    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;

    /**

     * activity 实际上是上下文的一个子类

     * @author Administrator

     *

     */

    public class MainActivity extends Activity {

    private EditText et_username;

    private EditText et_password;

    private CheckBox cb_remeber_pwd;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    cb_remeber_pwd = (CheckBox) findViewById(R.id.cb_remeber_pwd);

    et_username = (EditText) findViewById(R.id.et_username);

    et_password = (EditText) findViewById(R.id.et_password);

    try {

    String result = LoginService.readUserInfoFromFile(this);

    String[] infos = result.split("##");

    et_username.setText(infos[0]);

    et_password.setText(infos[1]);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    /**

     * 登陆按钮的点击事件

     * @param view

     */

    public void login(View view){

    String username = et_username.getText().toString().trim();

    String password = et_password.getText().toString().trim();

    if(TextUtils.isEmpty(username)||TextUtils.isEmpty(password)){

    Toast.makeText(getApplicationContext(), "用户名或者密码不能为空", 0).show();

    return;

    }

    //检查是否勾选了cb

    if(cb_remeber_pwd.isChecked()){//记住密码

    try {

    LoginService.saveUserInfoToFile(this, username, password);

    Toast.makeText(this, "保存用户名密码成功", 0).show();

    } catch (Exception e) {

    e.printStackTrace();

    Toast.makeText(getApplicationContext(), "保存用户名密码失败", 0).show();

    }

    }

    }

    }

    5、把文件存放在SDCard

    使用ActivityopenFileOutput()方法保存文件,文件是存放在手机空间上,一般手机的存储空间不是很大,存放些小文件还行,如果要存放像视频这样的大文件,是不可行的。对于像视频这样的大文件,我们可以把它存放在SDCard。 SDCard是干什么的?你可以把它看作是移动硬盘或U盘。

    在模拟器中使用SDCard,你需要先创建一张SDCard卡(当然不是真的SDCard,只是镜像文件)。创建SDCard可以在Eclipse创建模拟器时随同创建,也可以使用DOS命令进行创建,如下:

    Dos窗口中进入android SDK安装路径的tools目录,输入以下命令创建一张容量为2GSDCard,文件后缀可以随便取,建议使用.img

    mksdcard 2048M D:AndroidToolsdcard.img

    在程序中访问SDCard,你需要申请访问SDCard的权限。

    AndroidManifest.xml中加入访问SDCard的权限如下:

    <!-- SDCard中创建与删除文件权限 -->

    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

    <!-- SDCard写入数据权限 -->

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

    要往SDCard存放文件,程序必须先判断手机是否装有SDCard,并且可以进行读写。

    注意:访问SDCard必须在AndroidManifest.xml中加入访问SDCard的权限

    if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){

             File sdCardDir = Environment.getExternalStorageDirectory();//获取SDCard目录

             File saveFile = new File(sdCardDir, itcast.txt);

    FileOutputStream outStream = new FileOutputStream(saveFile);

    outStream.write("传智播客".getBytes());

    outStream.close();

    }

    Environment.getExternalStorageState()方法用于获取SDCard的状态,如果手机装有SDCard,并且可以进行读写,那么方法返回的状态等于Environment.MEDIA_MOUNTED

    Environment.getExternalStorageDirectory()方法用于获取SDCard的目录,当然要获取SDCard的目录,你也可以这样写:

    File sdCardDir = new File("/mnt/sdcard"); //获取SDCard目录

    File saveFile = new File(sdCardDir, "itcast.txt"); 

    //上面两句代码可以合成一句: File saveFile = new File("/mnt/sdcard/itcast.txt");

    FileOutputStream outStream = new FileOutputStream(saveFile);

    outStream.write("传智播客test".getBytes());

    outStream.close();

    }

    package com.itheima.login.service;

    import java.io.BufferedReader;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.InputStreamReader;

    import android.content.Context;

    import android.content.SharedPreferences;

    import android.content.SharedPreferences.Editor;

    /**

     * 登陆相关的服务

     * 

     * @author Administrator

     * 

     */

    public class LoginService {

    // 上下文 其实提供了应用程序 的一个详细的环境信息包括 包名是什么 /data/data/目录在哪里.

    // we do chicken right

    /**

     * 保存用户信息到文件

     * 

     * @param username

     *            用户名

     * @param password

     *            密码

     */

    public static void saveUserInfoToFile(Context context, String username,

    String password) throws Exception {

    SharedPreferences sp = context.getSharedPreferences("config",

    Context.MODE_PRIVATE);

    Editor editor = sp.edit();

    editor.putString("username", username);

    editor.putString("password", password);

    editor.commit();

    }

    /**

     * 读取用户的用户名和密码

     * 

     * @return // zhangsan##123456

     */

    public static String[] readUserInfoFromFile(Context context)

     {

    SharedPreferences sp = context.getSharedPreferences("config",

    Context.MODE_PRIVATE);

    String username = sp.getString("username", "");

    String password = sp.getString("password", "");

    String[] infos = new String[2];

    infos[0] = username;

    infos[1] = password;

    return infos;

    }

    }

    获取SD卡空间

    package com.itheima.getsize;

    import java.io.File;

    import android.os.Bundle;

    import android.os.Environment;

    import android.os.StatFs;

    import android.app.Activity;

    import android.text.format.Formatter;

    import android.view.Menu;

    import android.widget.TextView;

    public class MainActivity extends Activity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

       File path = Environment.getExternalStorageDirectory();

               StatFs stat = new StatFs(path.getPath());

               long blockSize = stat.getBlockSize();//得到可用区块大小

               long availableBlocks = stat.getAvailableBlocks();//得到有多少可用区块

               

               long size =   blockSize*availableBlocks;

               

               String sizeStr = Formatter.formatFileSize(this, size);

               

              TextView tv_info =  (TextView) findViewById(R.id.tv_info);

              

              

              File path1 = Environment.getDataDirectory();

              StatFs stat1 = new StatFs(path1.getPath());

              long blockSize1 = stat1.getBlockSize();

              long availableBlocks1 = stat1.getAvailableBlocks();

              

              

              tv_info.setText("sd卡可用空间:"+sizeStr+" "+"内部存储空间:"+Formatter.formatFileSize(this, blockSize1*availableBlocks1));

    }

    }

    6使用pull解析XML文件

    面是本例子要解析的XML文件:

    文件名称:itcast.xml

    <?xml version="1.0" encoding="UTF-8"?>

    <persons>

    <person id=18">

    <name>allen</name>

    <age>36</age>

    </person>

    <person id=28">

    <name>james</name>

    <age>25</age>

    </person>

    </persons>

    例子定义了一个javabean用于存放上面解析出来的xml内容, 这个javabeanPerson,代码请见本页下面备注:

    public class Person {

    private Integer id;

    private String name;

    private Short age;

    public Integer getId() {

    return id;

    }

    public void setId(Integer id) {

    this.id = id;

    }

    public String getName() {

    return name;

    }

    public void setName(String name) {

    this.name = name;

    }

    public Short getAge() {

    return age;

    }

    public void setAge(Short age) {

    this.age = age;

    }

    }

    7、使用Pull解析器读取XML文件

    除了可以使用 SAXDOM解析XML文件之外,大家也可以使用Android内置的Pull解析器解析XML文件。 Pull解析器是一个开源的java项目,既可以用于android,也可以用于JavaEE。如果用在javaEE需要把其jar文件放入类路径中,因为Android已经集成进了Pull解析器,所以无需添加任何jar文件。android系统本身使用到的各种xml文件,其内部也是采用Pull解析器进行解析的。 Pull解析器的运行方式与 SAX 解析器相似。它提供了类似的事件,如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。跟SAX不同的是, Pull解析器产生的事件是一个数字,而非方法,因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型节点的值。

    使用Pull解析器读取itcast.xml的代码在本页下方备注

    Pull解析器的源码及文档下载网址:http://www.xmlpull.org/

    import org.xmlpull.v1.XmlPullParser;

    import android.util.Xml;

    import cn.itcast.xml.domain.Person;

    public class PullXMLReader {

    public static List<Person> readXML(InputStream inStream) {

    XmlPullParser parser = Xml.newPullParser();

    try {

    parser.setInput(inStream, "UTF-8");

    int eventType = parser.getEventType();

    Person currentPerson = null;

    List<Person> persons = null;

    while (eventType != XmlPullParser.END_DOCUMENT) {

    switch (eventType) {

    case XmlPullParser.START_DOCUMENT://文档开始事件,可以进行数据初始化处理

    persons = new ArrayList<Person>();

    break;

    case XmlPullParser.START_TAG://开始元素事件

    String name = parser.getName();

    if (name.equalsIgnoreCase("person")) {

    currentPerson = new Person();

    currentPerson.setId(new Integer(parser.getAttributeValue(null, "id")));

    } else if (currentPerson != null) {

    if (name.equalsIgnoreCase("name")) {

    currentPerson.setName(parser.nextText());// 如果后面是Text节点,即返回它的值

    } else if (name.equalsIgnoreCase("age")) {

    currentPerson.setAge(new Short(parser.nextText()));

    }

    }

    break;

    case XmlPullParser.END_TAG://结束元素事件

    if (parser.getName().equalsIgnoreCase("person") && currentPerson != null) {

    persons.add(currentPerson);

    currentPerson = null;

    }

    break;

    }

    eventType = parser.next();

    }

    inStream.close();

    return persons;

    } catch (Exception e) {

    e.printStackTrace();

    }

    return null;

    }

    }

    package com.itheima.xmlparser;

    import java.util.List;

    import android.app.Activity;

    import android.os.Bundle;

    import android.widget.TextView;

    import android.widget.Toast;

    import com.itheima.xmlparser.domain.CityInfo;

    import com.itheima.xmlparser.service.WeatherService;

    public class MainActivity extends Activity {

    private TextView tv_weatherinfo;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    tv_weatherinfo = (TextView) findViewById(R.id.tv_weatherinfo);

    try {

    List<CityInfo> infos = WeatherService.getCityInfos();

    StringBuilder sb  = new StringBuilder();

    for(CityInfo info : infos){

    String weather = info.toString();

    sb.append(weather+" ");

    }

    tv_weatherinfo.setText(sb.toString());

    } catch (Exception e) {

    e.printStackTrace();

    Toast.makeText(this, "解析天气信息失败", 0).show();

    }

    }

    }

    package com.itheima.xmlparser.service;

    import java.util.ArrayList;

    import java.util.List;

    import org.xmlpull.v1.XmlPullParser;

    import android.util.Xml;

    import com.itheima.xmlparser.domain.CityInfo;

    public class WeatherService {

    /**

     * 获取所有城市的天气信息

     * 

     * @return

     */

    public static List<CityInfo> getCityInfos() throws Exception{

    XmlPullParser parser = Xml.newPullParser();

    List<CityInfo> cityInfos = null;

    CityInfo cityInfo = null;

    //设置初始化参数 解析哪个流里面的内容  格式编码

    parser.setInput(WeatherService.class.getClassLoader()

    .getResourceAsStream("weather.xml"), "utf-8");

    int type = parser.getEventType();

    while(type!=XmlPullParser.END_DOCUMENT){

    switch (type) {

    case XmlPullParser.START_TAG: //文本开始标签

    if("citys".equals(parser.getName())){

    //初始化所有城市信息的集合

    cityInfos = new ArrayList<CityInfo>();

    }else if("city".equals(parser.getName())){

    cityInfo = new CityInfo();

    String id = parser.getAttributeValue(null, "id");

    cityInfo.setId(Integer.parseInt(id));

    }else if("weather".equals(parser.getName())){

    String weather = parser.nextText();

    cityInfo.setWeather(weather);

    }else if("name".equals(parser.getName())){

    String name = parser.nextText();

    cityInfo.setName(name);

    }else if("temp".equals(parser.getName())){

    String temp = parser.nextText();

    cityInfo.setTemp(temp);

    }else if("wind".equals(parser.getName())){

    String wind = parser.nextText();

    cityInfo.setWind(wind);

    }else if("pm".equals(parser.getName())){

    String pm = parser.nextText();

    cityInfo.setPm(Integer.parseInt(pm));

    }

    break;

    case XmlPullParser.END_TAG: //结束节点

    if("city".equals(parser.getName())){

    //一个城市的信息解析完毕了.

    cityInfos.add(cityInfo);

    cityInfo = null;

    }

    break;

    }

    //只要事件类型不是文档的结尾,需要不停的解析下一个节点

    type = parser.next();

    }

    return cityInfos;

    }

    }

    8、使用Pull解析器生成XML文件

    有些时候,我们需要生成一个XML文件,生成XML文件的方法有很多,如:可以只使用一个StringBuilder组拼XML内容,然后把内容写入到文件中;或者使用DOM API生成XML文件,或者也可以使用pull解析器生成XML文件,这里推荐大家使用Pull解析器。

    使用Pull解析器生成一个与itcast.xml文件内容相同的myitcast.xml文件,代码在本页下方备注

    使用代码如下(生成XML文件):

    File xmlFile = new File("myitcast.xml");

    FileOutputStream outStream = new FileOutputStream(xmlFile);

    OutputStreamWriter outStreamWriter = new OutputStreamWriter(outStream, "UTF-8");

    BufferedWriter writer = new BufferedWriter(outStreamWriter);

    writeXML(persons, writer);

    writer.flush();

    writer.close();

    如果只想得到生成的xml字符串内容,可以使用StringWriter

    StringWriter writer = new StringWriter();

    writeXML(persons, writer);

    String content = writer.toString();

    public static String writeXML(List<Person> persons, Writer writer){

        XmlSerializer serializer = Xml.newSerializer();

        try {

            serializer.setOutput(writer);

            serializer.startDocument("UTF-8", true);

          //第一个参数为命名空间,如果不使用命名空间,可以设置为null

            serializer.startTag("", "persons");

            for (Person person : persons){

                serializer.startTag("", "person");

                serializer.attribute("", "id", person.getId().toString());

                serializer.startTag("", "name");

                serializer.text(person.getName());

                serializer.endTag("", "name");

                serializer.startTag("", "age");

                serializer.text(person.getAge().toString());

                serializer.endTag("", "age");

                serializer.endTag("", "person");

            }

            serializer.endTag("", "persons");

            serializer.endDocument();

            return writer.toString();

        } catch (Exception e) {

            e.printStackTrace();

        }

        return null;

    }

    9、使用SharedPreferences进行数据存储

    很多时候我们开发的软件需要向用户提供软件参数设置功能,例如我们常用的QQ,用户可以设置是否允许陌生人添加自己为好友。对于软件配置参数的保存,如果是window软件通常我们会采用ini文件进行保存,如果是j2se应用,我们会采用properties属性文件或者xml进行保存。如果是Android应用,我们最适合采用什么方式保存软件配置参数呢?Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。使用SharedPreferences保存数据,其背后是用xml文件存放数据,文件存放在/data/data/<package name>/shared_prefs目录下:

    SharedPreferences sharedPreferences = getSharedPreferences("itcast", Context.MODE_PRIVATE);

    Editor editor = sharedPreferences.edit();//获取编辑器

    editor.putString("name", "传智播客");

    editor.putInt("age", 4);

    editor.commit();//提交修改

    生成的itcast.xml文件内容如下:

    <?xml version='1.0' encoding='utf-8' standalone='yes' ?>

    <map>

    <string name="name">传智播客</string>

    <int name="age" value="4" />

    </map>

    因为SharedPreferences背后是使用xml文件保存数据,getSharedPreferences(name,mode)方法的第一个参数用于指定该文件的名称,名称不用带后缀,后缀会由Android自动加上。方法的第二个参数指定文件的操作模式,共有四种操作模式,这四种模式前面介绍使用文件方式保存数据时已经讲解过。如果希望SharedPreferences背后使用的xml文件能被其他应用读和写,可以指定Context.MODE_WORLD_READABLEContext.MODE_WORLD_WRITEABLE权限。

    另外Activity还提供了另一个getPreferences(mode)方法操作SharedPreferences,这个方法默认使用当前类不带包名的类名作为文件的名称。

    10访问SharedPreferences中的数据

    访问SharedPreferences中的数据代码如下:

    SharedPreferences sharedPreferences = getSharedPreferences("itcast", Context.MODE_PRIVATE);

    //getString()第二个参数为缺省值,如果preference中不存在该key,将返回缺省值

    String name = sharedPreferences.getString("name", "");

    int age = sharedPreferences.getInt("age", 1);

    如果访问其他应用中的Preference,前提条件是:该preference创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE权限。如:有个<package name>cn.itcast.action的应用使用下面语句创建了preference

    getSharedPreferences("itcast", Context.MODE_WORLD_READABLE);

    其他应用要访问上面应用的preference,首先需要创建上面应用的Context,然后通过Context 访问preference ,访问preference时会在应用所在包下的shared_prefs目录找到preference 

    Context otherAppsContext = createPackageContext("cn.itcast.action", Context.CONTEXT_IGNORE_SECURITY);

    SharedPreferences sharedPreferences = otherAppsContext.getSharedPreferences("itcast", Context.MODE_WORLD_READABLE);

    String name = sharedPreferences.getString("name", "");

    int age = sharedPreferences.getInt("age", 0);

    如果不通过创建Context访问其他应用的preference,也可以以读取xml文件方式直接访问其他应用preference对应的xml文件,如: 

    File xmlFile = new File(/data/data/<package name>/shared_prefs/itcast.xml);//<package name>应替换成应用的包名

    登录保存到sp

    package com.itheima.login.service;

    import java.io.BufferedReader;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.InputStreamReader;

    import android.content.Context;

    import android.content.SharedPreferences;

    import android.content.SharedPreferences.Editor;

    /**

     * 登陆相关的服务

     * 

     * @author Administrator

     * 

     */

    public class LoginService {

    // 上下文 其实提供了应用程序 的一个详细的环境信息包括 包名是什么 /data/data/目录在哪里.

    // we do chicken right

    /**

     * 保存用户信息到文件

     * 

     * @param username

     *            用户名

     * @param password

     *            密码

     */

    public static void saveUserInfoToFile(Context context, String username,

    String password) throws Exception {

    SharedPreferences sp = context.getSharedPreferences("config",

    Context.MODE_PRIVATE);

    Editor editor = sp.edit();

    editor.putString("username", username);

    editor.putString("password", password);

    editor.commit();

    }

    /**

     * 读取用户的用户名和密码

     * 

     * @return // zhangsan##123456

     */

    public static String[] readUserInfoFromFile(Context context)

     {

    SharedPreferences sp = context.getSharedPreferences("config",

    Context.MODE_PRIVATE);

    String username = sp.getString("username", "");

    String password = sp.getString("password", "");

    String[] infos = new String[2];

    infos[0] = username;

    infos[1] = password;

    return infos;

    }

    }

    package com.itheima.login;

    import com.itheima.login.service.LoginService;

    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;

    /**

     * activity 实际上是上下文的一个子类

     * 

     * @author Administrator

     * 

     */

    public class MainActivity extends Activity {

    private EditText et_username;

    private EditText et_password;

    private CheckBox cb_remeber_pwd;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    cb_remeber_pwd = (CheckBox) findViewById(R.id.cb_remeber_pwd);

    et_username = (EditText) findViewById(R.id.et_username);

    et_password = (EditText) findViewById(R.id.et_password);

    String[] infos = LoginService.readUserInfoFromFile(this);

    et_username.setText(infos[0]);

    et_password.setText(infos[1]);

    }

    /**

     * 登陆按钮的点击事件

     * 

     * @param view

     */

    public void login(View view) {

    String username = et_username.getText().toString().trim();

    String password = et_password.getText().toString().trim();

    if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {

    Toast.makeText(getApplicationContext(), "用户名或者密码不能为空", 0).show();

    return;

    }

    // 检查是否勾选了cb

    if (cb_remeber_pwd.isChecked()) {// 记住密码

    try {

    LoginService.saveUserInfoToFile(this, username, password);

    Toast.makeText(this, "保存用户名密码成功", 0).show();

    } catch (Exception e) {

    e.printStackTrace();

    Toast.makeText(getApplicationContext(), "保存用户名密码失败", 0).show();

    }

    }

    }

    }

    设置界面

    package com.itheima.setting;

    import android.app.Activity;

    import android.content.Context;

    import android.content.SharedPreferences;

    import android.content.SharedPreferences.Editor;

    import android.os.Bundle;

    import android.view.View;

    import android.view.View.OnClickListener;

    import android.widget.CheckBox;

    import android.widget.RelativeLayout;

    public class MainActivity extends Activity {

    private RelativeLayout rl_sound;

    private CheckBox cb_status;

    private SharedPreferences sp;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    rl_sound = (RelativeLayout) findViewById(R.id.rl_sound);

    cb_status = (CheckBox) findViewById(R.id.cb_status);

    //初始化sp

    sp = this.getSharedPreferences("config", Context.MODE_PRIVATE);

    boolean checked = sp.getBoolean("checked", false);

    cb_status.setChecked(checked);

    rl_sound.setOnClickListener(new OnClickListener() {

    @Override

    public void onClick(View v) {

    //创建sharedpreference的编辑器

    Editor editor = sp.edit();

    if(cb_status.isChecked()){

    editor.putBoolean("checked", false);

    cb_status.setChecked(false);

    }else{

    cb_status.setChecked(true);

    editor.putBoolean("checked", true);

    }

    //操作完参数后 一定要记得commit();

    editor.commit();

    }

    });

    }

    }

  • 相关阅读:
    苹果新的编程语言 Swift 语言进阶(五)--控制流
    苹果新的编程语言 Swift 语言进阶(四)--字符串和收集类型
    苹果新的编程语言 Swift 语言进阶(三)--基本运算和扩展运算
    苹果新的编程语言 Swift 语言进阶(二)--基本类型
    第一篇 android架构是如何满足设计目标的?
    第三篇 android 应用开发模式之MVC模式及Observer模式
    第二篇 android应用开发模式之模板模式
    为什么带网格(mesh)的模型添加了刚体Rigidbody和MeshCollider,还是会从地板穿过去?
    Mecanim动画模型规范
    HTC Vive 体验的折腾经历
  • 原文地址:https://www.cnblogs.com/pangblog/p/3258063.html
Copyright © 2011-2022 走看看