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为数据存储提供了如下几种方式:

)文件

)SharedPreferences(参数)

)SQLite数据库

)内容提供者(Content provider)

)网络

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_READABLE和Context.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_READABLE和Context.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

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

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

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

mksdcard 2048M D:\AndroidTool\sdcard.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+"\n"+"内部存储空间:"+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内容, 这个javabean为Person,代码请见本页下面备注:

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文件

除了可以使用 SAX或DOM解析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+"\n");

}

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_READABLE和Context.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();

}

});

}

}

Android核心基础(二)的更多相关文章

  1. Android核心基础(手机卫士的一个知识点总结)

    注意:有些功能是需要权限的,在这里并没有写出来,在程序运行中,根据程序报的错误,添加相应的权限即可,里面的具体里面可能有一些小细节,没有明确的写出来,具体的需要在程序中自己调试,解决. 这个总结涵盖了 ...

  2. Android核心基础(四)

    1.联系人表结构 添加一条联系人信息 package com.itheima.insertcontact; import android.app.Activity; import android.co ...

  3. Android核心基础(十)

    1.音频采集 你可以使用手机进行现场录音,实现步骤如下: 第一步:在功能清单文件AndroidManifest.xml中添加音频刻录权限: <uses-permission android:na ...

  4. Android核心基础(五)

    1.仿网易新闻客户端 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xml ...

  5. Android核心基础

    第三代移动通讯技术(3rd Generation) ,支持高速数据传输的蜂窝移动通讯技术.3G与2G的主要区别是传输数据的速度. 1987年,第一台模拟制式手机(1G)问世,只能进行语音通话,型号:摩 ...

  6. Android核心基础(十一)

    1.Android的状态栏通知(Notification) 通知用于在状态栏显示消息,消息到来时以图标方式表示,如下: //获取通知管理器 NotificationManager mNotificat ...

  7. 2017-2018-2 20165236 实验四《Android开发基础》实验报告

    2017-2018-2 20165236 实验四<Android开发基础>实验报告 一.实验报告封面 课程:Java程序设计       班级:1652班       姓名:郭金涛     ...

  8. Android应用的核心基础

    Android4开发入门经典 之 第二部分:Android应用的核心基础 Android应用中的组件 Application Components Android应用中最主要的组件是: 1:Activ ...

  9. Android BLE与终端通信(二)——Android Bluetooth基础科普以及搜索蓝牙设备显示列表

    Android BLE与终端通信(二)--Android Bluetooth基础搜索蓝牙设备显示列表 摘要 第一篇算是个热身,这一片开始来写些硬菜了,这篇就是实际和蓝牙打交道了,所以要用到真机调试哟, ...

随机推荐

  1. 设置服务器远程连接mysql

    一直单人开发所以没有考虑过这方面,到新公司要做合作开发,所以要进行设置,然后开始自己搞 下面把过程罗列一下: 1)由于使用的云服务器 ,所以上面都配置好了,直接配置了mysql的命令行输入密码就可以进 ...

  2. JVM原理

    Java语言写的源程序通过Java编译器,编译成与平台无关的‘字节码程序’(.class文件,也就是0,1二进制程序),然后在OS之上的Java解释器中解释执行,而JVM是java的核心和基础,在ja ...

  3. 【C语言】printf函数详解

    C语言printf函数详解 一.相关基础知识 请求printf()打印变量的指令取决于变量的类型,例如打印整数用%d符号,打印字符用%c符号,这些符号称为转换说明(conversion specifi ...

  4. POOL

    #ifndef POOL_HHH #define POOL_HHH #include "common.h" /* simple and fast obj pool without ...

  5. The xor-longest Path

    The xor-longest Path Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3875   Accepted: 8 ...

  6. 【HTTP】Speed and Mobility: An Approach for HTTP 2.0 to Make Mobile Apps and the Web Faster

    This week begins face to face meetings at the IETF on how to approach HTTP 2.0 and improve the Inter ...

  7. 自己写的carousel

    可以 function appendRight() { //alert("right"); lastItem = itemsRight[urls.length - ]; first ...

  8. Prefixes and Suffixes

    Codeforces Round #246 (Div. 2) D:http://codeforces.com/contest/432/problem/D 题意:给你一个长度不超过10^5的字符串.要你 ...

  9. 【 UVALive - 5095】Transportation(费用流)

    Description There are N cities, and M directed roads connecting them. Now you want to transport K un ...

  10. 3.1日 重温JVM相关信息

    1.JDK.JRE.JVM的关系: JDK是java开发的必备工具箱,JDK其中有一部分是JRE,JRE是JAVA运行环境,JVM则是JRE最核心的部分. 2.JVM的组成: JVM由4大部分组成:C ...