本帖最后由 小鲁哥哥 于 2016-11-13 13:34 编辑
【济南中心】Android课程同步笔记day02:Android应用开发基础
Android 单元测试 测试分类: 一、根据是否知道源码 黑盒测试:不知道源码,是以用户的角度,从输入数据与输出数据的对应关系出发进行测试的。 白盒测试:知道源码,又称结构测试、透明盒测试、逻辑驱动测试或基于代码的测试。 二、根据测试粒度分类 方法测试:FunctionTest,粒度最低,测试单个方法。 单元测试:JunitTest方法里面会调用其他的方法。 联调测试:IntegrationTest后台与前台集成,各模块之间的集成测试。 三、根据测试次数分类 冒烟测试:顾名思义,把设备一直测试到冒烟为止。Android 下提供给我们一种冒烟测试的功能: Monkey Test 猴子测试,在命令行输入adb shell,进入Linux 命令行。测试整个系统命令:monkey 1000(事件的数量);测试某个程序:monkey -p 包名事件的数量 压力测试:PressureTest,给后台用的,主体向被观察者布置一定量任务和作业,借以观察个体完成任务的行为。 Android Junit: Android Junit的使用分为两种情形: 一、在已有的工程中添加单元测试功能 1. 创建一个类继承AndroidTestCase类。 2. 在AndroidManifest.xml 中添加指令集和测试库 指令集位于application 节点之外 [XML] 纯文本查看 复制代码 <instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.itheima.android.junit">
</instrumentation> 测试库位于application 节点内部。 [XML] 纯文本查看 复制代码 <uses-libraryandroid:name="android.test.runner"/> 二、创建测试工程测试其他工程 1.创建一个Android TestProject 工程 2. 在测试工程中编写测试类继承AndroidTestCase 3. 在该类中编写测试方法,不需要手动在AndroidManifest.xml中添加指令集和测试库
Log 日志工具类的使用Log.v(tag,msg); Log.d(tag,msg); Log.i(tag,msg); Log.w(tag,msg); Log.e(tag, msg);
存储数据[Java] 纯文本查看 复制代码 /data/data目录是应用程序的私有目录,默认只有本应用程序才能操作。
getFilesDir():获取/data/data/包名/files文件
openFileInput(String):获取data目录下指定文件的的输入流,直接打开/data/data/包名/files/String文件
openFileOutput("String", MODE_PRIVATE):获取data目录下指定文件的的输出流创建/data/data/包名/files/ String 文件
CheckBox.setChecked()设置checkBox的勾选状态 往SD卡中存储数据 [Java] 纯文本查看 复制代码 Environment.getExternalStorageDirectory.getPath()可以直接返回sdcard的根目录路径
添加权限
<uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> Demo
布局文件
[XML] 纯文本查看 复制代码 <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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" >
<EditText
android:id="@+id/et_username"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/input_usernmae" />
<EditText
android:id="@+id/et_password"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/input_password"
android:inputType="textPassword" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<CheckBox
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:id="@+id/cb_rem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/rem_password" />
<Button
android:paddingLeft="50dp"
android:paddingRight="50dp"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:id="@+id/bt_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/login" />
</RelativeLayout>
</LinearLayout>
代码
[Java] 纯文本查看 复制代码 public class MainActivity extends Activity implements View.OnClickListener {
private EditText mEtName;
private EditText mEtPwd;
private CheckBox mCbRem;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// a.获取所需的控件
mEtName = (EditText) findViewById(R.id.et_username);
mEtPwd = (EditText) findViewById(R.id.et_password);
mCbRem = (CheckBox) findViewById(R.id.cb_rem);
Button bt_login = (Button) findViewById(R.id.bt_login);
// b.设置按钮的点击事件
bt_login.setOnClickListener(this);
// h.下次打开该界面时,将保存的用户名密码回显到EditText
Map<String, String> map = UserUtils.getUserInfo(this);
if (map != null) {
String username = map.get("username");
String password = map.get("password");
mEtName.setText(username);//设置EDitText的文本
mEtPwd.setText(password);
mCbRem.setChecked(true);//设置CheckBox选中
}
}
//控件点击时执行
@Override
public void onClick(View v) {
login();//执行登录
}
private void login() {
// c.在点击时获取用户输入的用户名,密码,是否记住密码
String username = mEtName.getText().toString().trim();
String password = mEtPwd.getText().toString().trim();
boolean isChecked = mCbRem.isChecked();
// d.判断用户名密码是否为null ,null提示用户
if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {
Toast.makeText(getApplicationContext(), "用户名密码不能为null", Toast.LENGTH_SHORT).show();
return;
}
// e.执行登陆(默认登录成功,省略)
// f.判断是否记住密码
if (isChecked) {
//判断sdcard的状态
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//sdcard不可用
Toast.makeText(getApplicationContext(), "sdcard未挂载或不存在", Toast.LENGTH_SHORT).show();
return;
}
//判断sdcard的剩余空间
File sdcard_filedir = Environment.getExternalStorageDirectory();//获取sdcard目录文件对象
long usableSpace = sdcard_filedir.getUsableSpace();//获取sdcard可用空间
long totalSpace = sdcard_filedir.getTotalSpace();
String usableSpace_str = Formatter.formatFileSize(this, usableSpace);
String totalSpace_str = Formatter.formatFileSize(this, totalSpace);
if (usableSpace < 200 * 1024 * 1024) {//小于200M
Toast.makeText(getApplicationContext(), "sdcard空间不足,总空间:" + totalSpace_str + " ; 剩余空间为:" + usableSpace_str, Toast.LENGTH_SHORT).show();
return;
}
// g.记住密码,将用户名密码保存起来。
boolean result = UserUtils.saveUserInfo(this, username, password);
if (result) {
Toast.makeText(getApplicationContext(), "保存成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "保存失败", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getApplicationContext(), "无需保存", Toast.LENGTH_SHORT).show();
}
}
}
工具类
[Java] 纯文本查看 复制代码 public class UserUtils {
//保存用户名密码
public static boolean saveUserInfo(Context context, String username, String password) {
try {
String info = username + "##" + password;
//创建文件要保存的流
String path = Environment.getExternalStorageDirectory().getPath();//得到一个外部存目录的路径
File file = new File(path, "userinfo.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
//将username password写入文件
fileOutputStream.write(info.getBytes());
fileOutputStream.close();
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
//获取保存的用户名密码
public static Map<String, String> getUserInfo(Context context) {
Map<String, String> map = new HashMap<String, String>();
try {
String path = Environment.getExternalStorageDirectory().getPath();//得到一个外部存目录的路径
File file = new File(path, "userinfo.txt");
FileInputStream fileInputStream = new FileInputStream(file);
//包装流,可以读取一行
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
String readLine = bufferedReader.readLine();
String[] split = readLine.split("##");
map.put("username", split[0]);
map.put("password", split[1]);
bufferedReader.close();
return map;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
SharedPreferences 一个轻量级的存储类,一般应用程序都会提供“设置”或者“首选项”等界面的设置就可以通过sp来保存。在Android 系统中该文件保存在:/data/data/包名/shared_prefs目录下。 [Java] 纯文本查看 复制代码 //获取SD卡的状态[/align]Environment.getExternalStorageState();
//根据获取的状态判断是否挂载了SD卡
Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
File file = Environment.getExternalStorageDirectory();
// 获取总字节数
longtotalSpace = file.getTotalSpace();
// 获取可用字节数
longfreeSpace = file.getFreeSpace();
Formatter.formatFileSize(Context,long);该类可以根据当前上下文将字节长度转换为用户易读的字符串文本。 获取SharedPreferences的三种方法: [Java] 纯文本查看 复制代码 1. PharedPreferences pre = context.getSharedPreferences("info",MODE_PRIVATE);
2. PharedPreferences pre = Activity.getPreferences(int mode);
3. PharedPreferences pre = PreferenceManager.getDefaultSharedPreferences(Context) SharedPreferences的用法: [Java] 纯文本查看 复制代码 1.获取SharedPreferences对象
PharedPreferences sp=context.getSharedPreferences("info",MODE_PRIVATE)
2.获取edit文本编辑对象
Editor edit = sp.edit();
3.添加数据
Editor editor =edit.putString("name", name)
4.提交
editor.commit();
文件的权限在Linux 中一个文件一共有三个组别:用户、群组、其它。其中每个组包含三种权限:读r、写w、执行x ,也就是说一个文件共有9 个权限属性 文件类型: d文件夹 ,l快捷方式,-文件
Xml 格式数据的生成和解析生成XML文件 第一种拼接字符串方式: [Java] 纯文本查看 复制代码 public static booleanbackupSms(Context context,ArrayList<SmsBean> lists) {[/align]
StringBuffersb = new StringBuffer();
//1.拼装一个xml的声明头
sb.append("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>");
//2.拼装一个根节点
sb.append("<Smss>");
//3.循环遍历list集合拼装一条条短信
for (SmsBean bean : lists) {
sb.append("<Sms id = \""+bean.id+"\">");
sb.append("<num>");
sb.append(bean.num);
sb.append("</num>");
sb.append("<msg>");
sb.append(bean.msg);
sb.append("</msg>");
sb.append("<date>");
sb.append(bean.date);
sb.append("</date>");
sb.append("</Sms>");
}
//4.拼装根节点的结束节点
sb.append("</Smss>");
//5.将xml字符串写入文件。
try{
FileOutputStreamopenFileOutput = context.openFileOutput("backupSms.xml", Context.MODE_PRIVATE);
openFileOutput.write(sb.toString().getBytes());
openFileOutput.close();
return true;
}catch (Exception e) {
e.printStackTrace();
}
return false;
} 第二种使用XmlSerializer生成Xml 文件 [Java] 纯文本查看 复制代码 public static booleanbackupSmsForAndroid(Contextcontext,ArrayList<SmsBean> lists) {
try{
//1.通过xml创建一个XmlSerializer对象
XmlSerializernewSerializer = Xml.newSerializer();
//2.设置XmlSerializer对象要写入哪个xml文件os:流信息encoding:流的编码
newSerializer.setOutput(context.openFileOutput("backupSms2.xml", Context.MODE_PRIVATE), "utf-8");
//3.序列化一个xml声明头 encoding:xml文件的编码 standalone:是否独立
newSerializer.startDocument("utf-8", true);
//4.序列化一个根几点 namespace:命名空间 name:标签名称
newSerializer.startTag(null, "Smss");
//5.循环遍历list集合序列化一条条短信
for (SmsBean bean : lists) {
newSerializer.startTag(null, "Sms");
newSerializer.attribute(null, "id", bean.id);//序列化一个属性
newSerializer.startTag(null, "num");
newSerializer.text(bean.num);
newSerializer.endTag(null, "num");
newSerializer.startTag(null, "msg");
newSerializer.text(bean.msg);
newSerializer.endTag(null, "msg");
newSerializer.startTag(null, "date");
newSerializer.text(bean.date);
newSerializer.endTag(null, "date");
newSerializer.endTag(null, "Sms");
}
//6.序列化根节点的结束节点
newSerializer.endTag(null, "Smss");
//7.完成xml的写入
newSerializer.endDocument();
return true;
}catch (Exception e) {
e.printStackTrace();
}
return false;
} 使用Pull 解析Xml 格式数据 [Java] 纯文本查看 复制代码 public static intrestoreSms(Context context) {
ArrayList<SmsBean> list = null;
SmsBeansmsBean = null;
try{
//1.使用Xml创建一个XmlpullParser对象
XmlPullParserxpp = Xml.newPullParser();
//2.告诉XmlpullParser对象要解析的是哪个文件inputStream:解析哪个文件的流信息inputEncoding:流的编码
xpp.setInput(context.openFileInput("backupSms2.xml"), "utf-8");
//3.获取当前xml第一行的事件类型
int type = xpp.getEventType();
//4.循环判断事件类型是否是文档结束标记
while (type != XmlPullParser.END_DOCUMENT) {
//获取当前标签的名称
String currentTagName = xpp.getName();
//5.如果不是文档结束,解析内容,并获取下一行的事件类型
switch (type) {
caseXmlPullParser.START_TAG:
if("Smss".equals(currentTagName)){
//初始化list集合
list = new ArrayList<SmsBean>();
}else if("Sms".equals(currentTagName)){
//创建一个SmsBean对象来封装数据
smsBean = new SmsBean();
smsBean.id = xpp.getAttributeValue(null, "id");//获取id属性的值
}else if("num".equals(currentTagName)){
smsBean.num = xpp.nextText();//当前标签是开始标签,并且下一个标签是Text标签,使用该方法获取下个Text中的值
} else if("msg".equals(currentTagName)){
smsBean.msg = xpp.nextText();//当前标签是开始标签,并且下一个标签是Text标签,使用该方法获取下个Text中的值
} else if("date".equals(currentTagName)){
smsBean.date = xpp.nextText();//当前标签是开始标签,并且下一个标签是Text标签,使用该方法获取下个Text中的值
}
break;
caseXmlPullParser.END_TAG:
if("Sms".equals(currentTagName)){
//当前标签是Sms的一个结束标签,说明一条短信封装完成,可以添加到list中
list.add(smsBean);
}
default:
break;
}
//6.并获取下一行的事件类型
type = xpp.next();
}
//7.短信封装完成,xml解析完了
return list.size();
}catch (Exception e) {
e.printStackTrace();
}
return 0;
} Pull 解析和SAX 解析对比 Pull 解析器的运行方式与SAX 解析器相似,都属于事件驱动模式。它提供了类似的事件,如:开始元 素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送, 因此可以使用一个switch 对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获 取下一个Text 类型元素的值。 SAX 解析器的工作方式是自动将事件推入事件处理器进行处理,因此你不能控制事件的处理主动结 束;而Pull 解析器的工作方式为允许你的应用程序代码主动从解析器中获取事件,正因为是主动获取事件, 因此可以在满足了需要的条件后不再获取事件,结束解析。
|