Android基础笔记(二)

  • 测试的相关概念
  • Android中的单元测试
  • 日志猫的介绍
  • 登陆案例
  • 把数据保存到SD卡上
  • Android中几个常用的目录
  • 获取SD卡的大小及可用空间
  • 文件权限的概念
  • SharedPreferences使用
  • Android官方推荐的生成XML的方式
  • Android官方推荐的解析XML的方式

测试的相关概念

好的程序不是开发出来的,是测试出来的。

根据是否知道源程序源码:
黑盒测试:不知源码,只是测试程序的功能
白盒测试:知道源码,根据源代码进行测试
根据测试的粒度:(模块的大小)
单元测试:unit test
功能测试:function test
集成测试:integration test :几个模块的测试,服务器/客户端的联调
系统测试:system test: JavaEE企业级开发中常常用到
根据测试的次数:(暴力测试)
① 冒烟测试:smoke test,不停的执行操作,直到系统崩溃
② 猴子测试,测试方法如下

Adb shell:进入模拟器目录,monkey 2000,通过monkey是随机点击2000次


# monkey –p 包名 次数:只测试某个应用程序

adb shell
monkey -p com.bzh.beijingwisdom 2000
③ 压力测试:pressure test

Android中的单元测试

手动增加单元测试的步骤
① 写一个类继承AndroidTestCase

② 在清单文件中增加指令集

<instrumentation
    android:name="android.test.InstrumentationTestRunner"
    android:targetPackage="程序包名" >
</instrumentation>

③ 在清单文件下的application节点下增加测试库

<uses-library android:name="android.test.runner"/>
创建Android测试工程进行测试

创建工程


创建后的清单文件

日志猫的介绍

Android LogCat的获取有两种方式:
1、DDMS提供的LogCat视图
2、通过adb命令行
DDMS提供的LogCat视图如下
① 如果该视图没有打开,点击window->showview->other->android->Logcat来进行选择


② 视图的左侧可以选择或者添加过滤信息,运行一个应用程序时,此处会默认创建一个该包的过滤。视图的右上角区域用于选择LogCat的log级别,共有verbose、debug、info、warn、error、assert6个可选项。如图所示:


③该视图的主体部分是log的详细信息,包括错误级别(Level)、时间(Time)、进程ID(PID)、线程ID(TID)、应用程序包名(Application)、标签(Tag)、日志正文(Text)。

其中的TID并不等同于Java中的Thread.currentThread().getId(),而是我们Linux中的Thread ID,跟PID相同。

LogCat日志的级别及使用
android.util.Log常用的方法有以下5个:
Log.v() Log.d() Log.i() Log.w() 以及 Log.e() 。
根据首字母对应VERBOSE,DEBUG,INFO, WARN,ERROR。
  1. Log.v 的调试颜色为黑色的,任何消息都会输出,这里的v代表verbose啰嗦的意思,平时使用就是Log.v(“”,”“);
  2. Log.d的输出颜色是蓝色的,仅输出debug调试的意思,但他会输出上层的信息,过滤起来可以通过DDMS的Logcat标签来选择.
  3. Log.i的输出为绿色,一般提示性的消息information,它不会输出Log.v和Log.d的信息,但会显示i、w和e的信息,System.out输出信息是Info级别
  4. Log.w的意思为橙色,可以看作为warning警告,一般需要我们注意优化Android代码,同时选择它后还会输出Log.e的信息。
  5. Log.e为红色,可以想到error错误,这里仅显示红色的错误信息,这些错误就需要我们认真的分析,查看栈的信息了。
  6. 程序中我们可以使用Log类来输出信息

    结果:

登陆案例

获取/data/data/com.xxx.xxx/files路径

String savePath  = MainActivity.this.getFilesDir().getPath();

直接使用AndroidAPI获取内部存储路径的输入、输出流

// 1
FileInputStream fis = context.openFileInput("info3.txt");
// 2
FileOutputStream fos = context.openFileOutput("info3.txt", Context.MODE_PRIVATE);

把数据保存到SD卡上

增加权限

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

获取SD卡的存储路径

String savePath = Environment.getExternalStorageDirectory().getPath();

Android中几个常用的目录

内部应用程序的默认文件路径
使用的API:context.getFilesDir().getPath()

路径:/data/data/com.itheima.getsdavail/files

// /data/data/com.itheima.getsdavail/files
Log.i(TAG, "内部应用程序的默认文件目录:" + getFilesDir().getPath());
内部应用程序的默认缓存路径
使用的API:context.getCacheDir().getPath()

路径:/data/data/com.itheima.getsdavail/cache

// /data/data/com.itheima.getsdavail/cache
Log.i(TAG, "内部应用程序的默认缓存目录:" + getCacheDir().getPath());
SD卡应用程序的默认文件目录
使用的API:context.getExternalFilesDir(null).getPath()

路径:/mnt/sdcard/Android/data/com.itheima.getsdavail/files

// /mnt/sdcard/Android/data/com.itheima.getsdavail/files
Log.i(TAG, "SD卡应用程序的默认文件目录:" + getExternalFilesDir(null).getPath());
SD卡应用程序的默认缓存目录
使用的API:context.getExternalCacheDir().getPath()

路径:/mnt/sdcard/Android/data/com.itheima.getsdavail/cache

// /mnt/sdcard/Android/data/com.itheima.getsdavail/cache
Log.i(TAG, "SD卡应用程序的默认缓存目录:" + getExternalCacheDir().getPath());
SD卡根路径
使用的API:Environment.getExternalStorageDirectory().getPath()

路径:/mnt/sdcard

// /mnt/sdcard
Log.i(TAG, "SD卡根路径:" + Environment.getExternalStorageDirectory().getPath());

获取SD卡的大小及可用空间

Andoird2.3版本以上的获取方法

// 获取到SD卡目录
File file = Environment.getExternalStorageDirectory();

TextView tvTotal = (TextView) findViewById(R.id.tv_total);
// 获取SK卡目录的总共空间大小,返回值为long型
long totalSpace = file.getTotalSpace();
// 使用AndroidAPI进行数据的格式化
String total = Formatter.formatFileSize(this, totalSpace);

tvTotal.setText(total);

TextView tvAvail = (TextView) findViewById(R.id.tv_avail);
// 获取SK卡目录的可用空间大小,返回值为long型
long usableSpace = file.getUsableSpace();
// 使用AndroidAPI进行数据的格式化
String avail = Formatter.formatFileSize(this, usableSpace);

tvAvail.setText(avail);

兼容Andoird2.2版本的获取方法

/**
* 获取手机外部可用空间大小
 *
 * @return
 */
public static long getAvailableExternalMemorySize() {
    // 判断SD卡是否可用
    if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
        // 获取SD卡目录
        File path = Environment.getExternalStorageDirectory();
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSize();
        long availableBlocks = stat.getAvailableBlocks();
        return availableBlocks * blockSize;
    } else {
        throw new RuntimeException("Don‘t have sdcard.");
    }
}
/**
 * 获取手机外部空间大小
 *
 * @return
 */
public static long getTotalExternalMemorySize() {
    if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
        File path = Environment.getExternalStorageDirectory();// 获取外部存储目录即
                                                                // SDCard
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSize();
        long totalBlocks = stat.getBlockCount();
        return totalBlocks * blockSize;
    } else {
        throw new RuntimeException("Don‘t have sdcard.");
    }
}

文件权限的概念

以下是一个典型linux下目录文件权限图

Linux下目录文件权限由10位组成
第 1 位:d为目录,-为文件
2 - 4位(当前用户):r为读权限,w为写权限,x 为可执行权限
5 - 7位(当前用户所在组):r为读权限,w为写权限,x 为可执行权限
8 - 10为(其他用户):r为读权限,w为写权限,x 为可执行权限

简图如下

创建私有、追加、可读、可写权限的文件
主要是通过context.openFileOutput()方法的第二个参数进行设置
①私有

代码如下

public void Private(View v) throws Exception {
    FileOutputStream fos = context.openFileOutput("Private.txt", MODE_PRIVATE);
    fos.write("Private".getBytes());
    fos.close();
}
截图,可以看到私有的在其他用户组中的权限为- - -

②可追加

代码如下

FileOutputStream fos = openFileOutput("Append.txt", MODE_APPEND);
fos.write("Append".getBytes());
fos.close();
截图,可以看到可追加的在其他用户组中的权限为- - -,与私有的一致,可追加和私有的权限,并不能在文件权限中体现出来。

③可读

代码如下

FileOutputStream fos = openFileOutput("Read.txt", MODE_WORLD_READABLE);
fos.write("Read".getBytes());
fos.close();
截图,可以看到可读的在其他用户组中的权限为r - -

④可写

代码如下

FileOutputStream fos = openFileOutput("Write.txt", MODE_WORLD_WRITEABLE);
fos.write("Write".getBytes());
fos.close();
截图,可以看到可写的在其他用户组中的权限为- r -

SharedPreferences使用

使用步骤

① 通过上下文的API获取到SharedPreferences实例

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

② 通过SharedPreferences.Editor存储数据

Editor editor = sp.edit();
editor.putString("username", username);
editor.putString("password", password);

③ 通过Editor提交数据

editor.commit();

④ 使用SharedPreferences实例对象获取key对应的数据

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

使用SharedPreferences创建的文件如下图

可以看到使用SP存储文件,在内部应用程序目录下创建了shared_prefs文件夹,并在文件夹下以指定的权限,创建了一个XML文件。

Android官方推荐的生成XML的方式

使用步骤
① 生成一个xml序列化器
② 设置序列化参数
③ 开始文档
④ 生成根节点
⑤ 循环生成子节点元素

具体代码如下,写的有详细注释:

// 1. 生成一个xml序列化器
XmlSerializer xmlSerializer = Xml.newSerializer();
// 2. 设置序列化参数,参数1:xml文件输出流;参数2:xml文件编码格式
FileOutputStream fos = openFileOutput("users.xml", Context.MODE_PRIVATE);
xmlSerializer.setOutput(fos, "UTF-8");
// 3. 开始文档,参数1:XML文档中第一行的encoding内容;参数2:是否是独立的,不依赖约束
xmlSerializer.startDocument("UTF-8", true);
// 4. 生成users根节点
xmlSerializer.startTag(null, "users");
// 5. 循环生成user子节点元素
for (User user : userList) {
    xmlSerializer.startTag(null, "user");
    // 6. 设置标签属性
    xmlSerializer.attribute(null, "id", user.getId());
    // 7. 设置user属性
    xmlSerializer.startTag(null, "name");
    xmlSerializer.text(user.getName());
    xmlSerializer.endTag(null, "name");
    // 8. 设置password属性
    xmlSerializer.startTag(null, "password");
    xmlSerializer.text(user.getPassword());
    xmlSerializer.endTag(null, "password");
    xmlSerializer.endTag(null, "user");
}
xmlSerializer.endTag(null, "users");
xmlSerializer.endDocument(); // 当文档结束时,会把输出流刷新,所有数据输出到文件中。

序列化后的XML文件如下:

Android官方推荐的解析XML的方式

使用步骤:
① 得到Xml解析器
② 得到Xml解析器参数
③ 获取事件,XMLPull是类似于SAX的基于事件、一行一行解析的
④ 循环处理事件
⑤ 处理根节点、子节点、子节点元素等

代码如下:

List<User> userList = null;
User user = null;
// 1. 得到Xml解析器
XmlPullParser parser = Xml.newPullParser();
// 2. 设置解析器
InputStream in = getClass().getClassLoader().getResourceAsStream(
        "users.xml");
// 参数1:解析的文件流;参数2:解析XML的编码格式
parser.setInput(in, "UTF-8");
// 3. 获取事件,XMLPull是类似于SAX的基于事件、一行一行解析的
int eventType = parser.getEventType();
// 4. 循环处理事件
while (eventType != XmlPullParser.END_DOCUMENT) {
    switch (eventType) {

    case XmlPullParser.START_TAG:
        if ("users".equals(parser.getName())) {
            // 根节点时,初始化集合
            userList = new ArrayList<User>();
        } else if ("user".equals(parser.getName())) {
            // 子元素时,初始化对象
            user = new User();
            // 获取子元素中的属性
            String id = parser.getAttributeValue(0);
            user.setId(id);
        } else if ("name".equals(parser.getName())) {
            String name = parser.nextText();
            user.setName(name);
        } else if ("password".equals(parser.getName())) {
            String password = parser.nextText();
            user.setPassword(password);
        }
        break;

    case XmlPullParser.END_TAG:
        if ("user".equals(parser.getName())) {
            // 将元素添加到集合中
            userList.add(user);
        }
        break;
    default:
        break;
    }
    eventType = parser.next();
}

System.out.println(userList.toString());

时间: 2024-08-23 07:41:10

Android基础笔记(二)的相关文章

Android学习笔记二十九之SwipeRefreshLayout、RecyclerView和CardView

Android学习笔记二十九之SwipeRefreshLayout.RecyclerView和CardView 前面我们介绍了AlertDialog和几个常用的Dialog,ProgressDialog进度条提示框.DatePickerDialog日期选择对话框和TimePickerDialog时间选择对话框.这一节我们介绍几个新的API控件SwipeRefreshLayout.RecyclerView和CardView,这几个API控件都是google在Android5.0推出的.下面我们来学

Android学习笔记二

17. 在ContentProvider中定义的getType()方法是定义URI的内容类型. 18. SQLiteDatabase类中的insert/delete/update/query方法其实也挺好用的,我在EquipmentProvider类中做了实现 19. Android专门有个单元测试项目(Android Test Project),在这个项目中,可以新建一个继承AndroidTestCase类的具体测试类来单元测试某个功能.我新建了一个AndroidTestProject项目,在

Java for Android 基础笔记-数据类型

Java的基本数据类型 布尔类型 boolean true | false java是一个强类型的语言,与JS中的布尔类型的自由转换相比,JAVA的Boolean类型只有两种true和false,JS中相应的只可以自行转换. 字符类型 char 可以存储一个汉字,和其他语言非常类似不再赘述. 整型 byte, 占用一个字节 -128`-127 short 2字节 -2^15~2^15-1 int 4字节 -2^31~2^31-1 long 8字节  -2^63~2^63-1 整型常量默认为int

Android学习笔记二十之Toast吐司、Notification通知、PopupWindow弹出窗

Android学习笔记二十之Toast吐司.Notification通知.PopupWindow弹出窗 Toast吐司 Toast吐司是我们经常用到的一个控件,Toast是AndroidOS用来显示消息的一种机制,它与Dialog不同,Toast不会获取到焦点,通常显示一段时间之后就会自动消失,下面我们来介绍Toast的几种常用方式: 第一种,默认显示方式,也是最常用的方式: Toast.makeText(MainActivity.this, "这是默认的显示方式", Toast.LE

Android学习笔记二十五之ListView多布局实现

Android学习笔记二十五之ListView多布局实现 这一节是介绍ListView这个控件的最后一节,实现一个Item的多布局.像我们经常在用的各种即时通讯工具,QQ.微信等,假设他们的会话界面是ListView实现的,那么ListView就有多种Item布局,这一节,我们就来实现一个ListView的多种Item. 要实现ListView里面有多种Item,就要重写适配器的两个方法getViewTypeCount()和getItemViewType(int position),第一个方法是

Android学习笔记二十四之ListView列表视图二

Android学习笔记二十四之ListView列表视图二 前面一篇我们介绍了常用的几种适配器的简单实现和ListView的简单使用,这一篇中,我们介绍一下ListView的优化和一些其它的问题. ListView优化方法一 在ListView中,我们最常用的就是自定义Adapter,在我们自定义Adapter中,需要实现两个比较重要的方法getCount()和getView(),前者是负责计算ListView的总Item数,后者是生成Item,有多少个Item就会调用getView()方法多少次

Android学习笔记二十七之ExpandableListView可折叠列表和StackView栈视图

Android学习笔记二十七之ExpandableListView可折叠列表和StackView栈视图 ExpandableListView可折叠列表 这一节我们介绍第三个用适配器的控件,ExpandableListView可折叠列表.这个控件可以实现我们在QQ中非常常见好友分组功能,ExpandableListView是ListView的子类,用法跟ListView差不多,下面我们来学习这个控件的基本使用: 常用属性: android:childDivider:指定各组内子类表项之间的分隔条,

Android 面试题总结之Android 基础(二)

Android 面试题总结之Android 基础ContentProvider(二) 在上一章节Android 面试题总结之Android 基础Activity(一) 我们讲的Activity基础知识.有许多朋友反映看着比较乱,我又回去看了看 ,确实很乱,不够细心.然后我又重新整理了一遍.让大家阅读体验更好! 在阅读过程中有任何问题,请及时联系. 本章系<Android 之美 从0到1 – 高手之路>Android基础ContentProvider 总结了Android 开发者面试比较常见的C

Android学习笔记二-Linear Layout

1.LinearLayout是子view均为单方向的,即均为水平或垂直方向的布局.你可以用android:orientation属性来 定义layout方向 所有子view都是一个挨着一个的,所以一个垂直列表,不管它本身多宽,同时只能有一行.若是水平列表,则都等高. 2.LayoutWeight 用来操控各个子view的相对比例,,即各个子元素对空间的使用权重 Weight并非网上很多文章所叙述的那样(文章都过于片面),weight是指某个组件在布局中[剩余空间]中的显示权重,那么所谓的剩余空间

Android学习笔记二十.使用ContentProvider实现数据共享(二).URI...工具类

一.UriMatcher与ContentUris工具类 UriMatcher 1.功能概述 开发ContentProvider时所实现的query().insert().delete().update()方法的第一个参数为Uri参数,该参数由ContentResolver调用这些方法时传入.在上一篇博文中的实例,并没有真正对数据进行操作,因此ContentProvider并未对Uri参数进行任何判断.所以为了确定该ContentProvider实际能处理的Uri,以确定每个方法中Uri参数所操作