前言
从软件测试最终目的发现问题缺陷来看,Findyou比较认同一个观念,测试的能力大致可以划分成三个能力层次:发现问题、定位问题、预防问题。有机会探讨一下这个分类。
发现问题各种方式方法,比如边界值,如何有效提高发现问题的效率?比如APP前后台切换数据为什么容易丢失?什么情况下容易产生OOM?
定位问题要求测试综合能力强,你比如业务熟悉、代码熟悉、平台(比如Linux系统、Android系统)熟悉等均有很强的要求。比如上文的栗子,APP前后台切换界面录入数据丢失,能否通过日志、代码、系统机制定位到准确的原因,如何找?
这是一个日积月累的过程,今天我们先从了解Android系统的一些知识入门学起。
1
Android 四大组件
Android系统有四种组件,这四种组件构成了Android应用的框架,然后由Intent联系这四种组件。
Activity:直译为活动,用来显示Android的程序界面,一个应用往往有多个界面,所以一个应用中会有多个Activity。
Service:服务,没有界面的后台服务,会一直运行在后台。常被用来做数据处理,也可以做一些定时的任务。
Broadcast Receiver:广播接收器,在广播机制中充当广播的接受者的作用,Android中充满了各种广播,所有需要有选择地接收一些有用的广播,然后处理这些广播。
Content Provider:直译为内容提供者,它是用在不同的应用程序之间共享数据时,可以把一个应用的数据提供给其他的应用使用。
Intent:意图,描述应用想干什么。最重要的部分是动作和动作对应的数据。
2
Android 系统架构
应用程序层(Java应用程序):
该层提供一些核心应用程序包,例如电子邮件、短信、日历、地图、浏览器和联系人管理等。同时,开发者可以利用Java语言设计和编写属于自己的应用程序,而这些程序与那些核心应用程序彼此平等、友好共处。
框架层(JAVA框架):
该层是Android应用开发的基础,包括活动管理器、窗口管理器、内容提供者、视图系统、包管理器、电话管理器、资源管理器、位置管理器、通知管理器和XMPP服务十个部分。开发人员可以完全访问核心应用程序所使用的API框架。
系统库和android运行时层(本地框架和JAVA运行环境):
包含一些C/C++库,这些库能被Android系统中不同的组件使用。Android运行时包括核心库和Dalvik虚拟机,前者既兼容了大多数Java语言所需要调用的功能函数,又包括了Android的核心库,后者是一种基于寄存器的java虚拟机,Dalvik虚拟机主要是完成对生命周期的管理、堆栈的管理、线程的管理、安全和异常的管理以及垃圾回收等重要功能。
LINUX内核层
Android 的核心系统服务依赖于 Linux 2.6 内核,如安全性、内存管理、进程管理、网络协议栈和驱动模型。Linux内核也是作为硬件与软件栈的抽象层。驱动:显示驱动、摄像头驱动、键盘驱动、WiFi驱动、Audio驱动、flash内存驱动、Binder(IPC)驱动、电源管理等。
3
Activity生命周期
主要有7个方法:onCreate()、onStart()、onResume()、onPause()、onStop()、onRestart()、onDestroy()。
启动Activity:onCreate()--->onStart()--->onResume(),Activity进入运行状态。
Activity切入后台:onPause()--->onStop(),进入停滞状态。【操作】当前Activity跳转到新的Activity界面,或者按Home键回主屏。
Activity返回前台:onRestart()--->onStart()--->onResume(),再次回到运行状态。
Activity后台,系统内存不足终止,再启动:onCreate()-->onStart()--->onResume(),Activity进入运行状态。
锁定屏与解锁屏幕:只会调用onPause(),而不会调用onStop方法,开屏后则调用onResume()
横竖屏切换时 Activity 的生命周期 :此时的生命周期跟清单文件里的配置有关系。1、不设置 Activity 的 android:configChanges 时,切屏会重新调用各个生命周期默认首先销毁当前 activity,然后重新加载。2、设置 Activity
android:configChanges=”orientation|keyboardHidden|screenSize”时,切屏不会重新调用各个生命周期,只会执行 onConfigurationChanged 方法。 通常在游戏开发, 屏幕的朝向都是写死的。
4
Service生命周期
service的生命周期,从它被创建开始,到它被销毁为止,可以有两条不同的路径:
图转换为文字:
context.startService() ->onCreate()- >onStartCommand()->Service running--调用context.stopService() ->onDestroy()
context.bindService()->onCreate()->onBind()->Service running--调用>onUnbind() -> onDestroy()
通常分为两种服务:
本地服务, Local Service 用于应用程序内部。在Service可以调用Context.startService()启动,调用Context.stopService()结束。 在内部可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。无论调用了多少次startService(),都只需调用一次 stopService()来停止。
远程服务, Remote Service 用于android系统内部的应用程序之间。可以定义接口并把接口暴露出来,以便其他应用进行操作。客户端建立到服务对象的连接,并通过那个连接来调用服 务。调用Context.bindService()方法建立连接,并启动,以调用 Context.unbindService()关闭连接。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加 载它。
总结:
如果service是被开启的,那么它的活动生命周期和整个生命周期一同结束。
如果service是被绑定的,它们它的活动生命周期是在onUnbind()方法返回后结束。
5
Fragment生命周期
切换到该Fragment:onAttach--->onCreate--->onCreateView--->onActivityCreated--->onStart--->onResume
屏幕灭掉:onPause--->onSaveInstanceState--->onStop
屏幕解锁:onStart--->onResume
切换到其他Fragment:onPause--->onStop--->onDestroyView
切换回本身的Fragment:onCreateView--->onActivityCreated--->onStart--->onResume
回到桌面:onPause--->onSaveInstanceState--->onStop
回到应用:onStart--->onResume
退出应用:onPause--->onStop--->onDestroyView--->onDestroy--->onDetach
与Activity生命周期对比:
6
Activity四种启动模式
standard
模式启动模式,每次激活Activity时都会创建Activity,并放入任务栈中。
singleTop
如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。
singleTask
如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。
singleInstance
在一个新栈中创建该Activity实例,并让多个应用共享改栈中的该Activity实例。一旦改模式的Activity的实例存在于某个栈中,任何应用再激活改Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中。
模式之间的区别:
singleTop跟standard模式比较类似,singleTop跳转的对象是位于栈顶的activity(用户所见),程序将不会生成一个新的activity 实例,而是直接跳到现存于栈顶的那个activity 实例,按返回键程序将直接退出。
singleTask 模式和singleInstance模式都是只创建一个实例的。在这种模
式下,无论跳转的对象是不是位于栈顶的 activity,程序都不会生成一个新的实例(当然前提是栈里面已经有这个实例)。这种模式相当有用,在以后的多 activity 开发中,常会因为跳转的关系导致同个页面生成多个实例,这个在用户体验上始终有点不好,而如果你将对应的 activity 声明为singleTask 模式,这种问题将不复存在,在主页的 Activity 很常用。
7
Manifest.xml文件
Manifest.xml文件中主要包括:
manifest:根节点,描述了package中所有的内容。
uses-permission:请求你的package正常运作所需赋予的安全许可。
permission: 声明了安全许可来限制哪些程序能你package中的组件和功能。
instrumentation:声明了用来测试此package或其他package指令组件的代码。
application:包含package中application级别组件声明的根节点。
activity:Activity是用来与用户交互的主要工具。
receiver:IntentReceiver能使的application获得数据的改变或者发生的操作,即使它当前不在运行。
service:Service是能在后台运行任意时间的组件。
provider:ContentProvider是用来管理持久化数据并发布给其他应用程序使用的组件。
8
AIDL
在Android中,每个应用(Application)执行在它自己的进程中,无法直接调用到其他应用的资源,这也符合“沙箱”的理念。但各应用间需要交互通信,因此有了IPC(进程间通信)协议:AIDL。
实现步骤:
定义一个AIDL接口
为远程服务(Service)实现对应Stub
将服务“暴露”给客户程序使用
9
FC / Crash
Force close,或者Crash
常见原因
Error: OOM(out of memory error)
Error:StackOverFlowError
RuntimeException
10
Activity Not Respone
ANR,无响应
常见原因
1、当用户输入事件5s内没有得到响应,将弹出ANR对话框
2、广播接收者的onReceive()执行时间超过10s
基础知识
1、Main线程也称为UI线程、主线程
2、功能: 1.创建UI控件;2.更新UI控件状态; 3.事件处理
3、限制:Main线程不建议有超过5秒的事件
解决方案
1、所有可能的耗时操作都要在子线程()中执行
2、常见耗时操作:I/O,网络操作,SDcard,数据运算
3、子线程更新UI:handler+massage线程间通讯