第2讲 移动应用开发基础知识(二) 宋婕 sj@chzu.edu.cn
上讲回顾 Android王国的全景图 Android系统的常用四大组件 Android开发环境的搭建 Android的程序结构
教学目标 Android的程序结构深入学习 了解Android 应用程序生命周期 掌握Activity生命周期中回调函数的调用及Activity栈 掌握Android应用程序的调试方法和工具
Android程序结构 存放源代码 自动生成并存放资源文件的唯一ID 该项目支持的jar包以及打包时需要的meta-inf目录文件 存放不需要的.R文件管理的资源文件getResources.getAssets().open(“demo.txt”) 调试或发布时,程序的APK,这些资源包或一些临时文件 声音、图片、布局 不同分辨率 应用程序的布局文件:界面布局和样式 以xml存放的资源描述文件:字符串、样式、颜色的描述性文件 系统控制文件 系统自动生成,存放版本等信息,无需人为更改
程序生命周期 应用程序生命周期:应用程序进程从创建到消亡的整个过程 Android应用程序生死由“天”,不能主宰自己的命运。 根据应用程序的组件以及组件当前运行状态将所有的进程按重要性程度从高到低划分成五个: 前台进程 可见进程 服务进程 后台进程 空进程 在对一个简单的Hello World工程进行项目结构剖析后,我们接着来学习下一个Android应用程序的生命周期是怎么样的,以便为后面的开发有个垫下良好的基石~ 所谓的应用程序生命周期无非就是应用程序进程从创建到消亡的整个过程。但是,之所有将这一点拎出来单独的讲,当然有其特殊性。的确,Android应用程序的生命周期的终结这个动作并非由应用程序进程本身执行,而是取决于Android系统,也就是Android应用程序生死由“天”,不能主宰自己的命运。这与我们传统的编程思维可能有所程序,如最初学的C语言程序都是最后收到内部或者外部退出请求而运行中的进程从main函数通过return退出,而非由系统直接kill的,这样的情况很少。那么,Android的设计师们为什么如此设计呢?这样设计的好处是什么呢? 其实,主流智能手机大多数都是多任务型,笔者常常用自己的手机一边游戏一边听音乐同时可能还开着UCWeb和QQ,的确这样给用户带来的体验是无以伦比的。但是,一个不容忽视的问题就是,手机的内存只有那么多,随着我们打开的应用程序数量的增多,随之而来的可能会是应用程序响应时间过长或者系统假死的糟糕情况。所以,若将Android应用程序生命周期便交由系统处理的话,那么在系统内存不足的情况下,便由Android系统舍车保帅,选择性的来中止一些重要性较次的应用程序,以便回收内存供更重要的应用程序使用。 那么,系统是根据一个怎样的重要性标准来中止Android应用程序的呢?其实,Android中根据应用程序的组件以及组件当前运行状态将所有的进程按重要性程度从高到低划分成五个,如下图所示: ² 前台进程 顾名思义,前台进程就是在屏幕最前端显示并和用户交互的Activity进程或者该进程的一个BroadcastReceiver正在运行。这样的进程重要性最高,在系统中也 只有少数这样的进程。除非在系统内存非常低,万不得已的情况下才会被中止,否则系统不会选择中止前台进程。 一般而言,满足以下条件之一即可视为前台进程 1) 进程正在最前端运行一个和用户交互的Activity(其OnResume()方法将被调用) 2) 进程有一个正在运行的BroadcastReceiver(它的BroadcastRecevicer.onReceive()方法正在被执行) 3) 进程有一个Service,并且在Service的某个回调函数内正有执行的代码 ² 可见进程 可见进程是指那些对于用户可见,但是不显示在屏幕的最前端的进程。可见进程的重要程度也是很高的,通常不会被系统所中止,除非处于舍车保帅的情况, 为了保持所有的前台进程的正常运行而不得不中止可见进程。 一般而言,满足以下条件之一即可视为可见进程 1)有一个非前台但是仍然对用户可见的activity(onPause()方法被调用)。例如:当前的前台的activity是一个对话框,上一个activity还是可见的 2)具有一个绑定到可见activity的service ² 服务进程 服务进程是拥有Service的进程,该Service是有startService()方法启动的,这些进程通常运行在后台,并且对用户是不可见的。但是,这些进程所作的工 作却也是比较重要的,如在后台进行播放音乐的工作。所以,除非在保证前两种高级别的进程能正常工作的情况下,否则系统一般不会中止服务进程的。 ² 后台进程 后台进程运行着对用户不可见的activity(调用过onStop()方法),这些进程对用户体验没有直接的影响,可以在上述进程需要内存资源的时候,从后台进程 这回收。通常,系统中有很多的不可见的进程在运行,这些都保存在LRU(least last used)列表中,以便内存不足的时候会在第一时间被回收。当需要中止进程 的时候,系统会保证最近一个被用户看到的进程最后一个被中止。 ² 空进程 在空进程中无任何的应用程序组件,而这种进程存在的唯一理由是提供一种缓存机制,使得缩短应用程序下次启动所需的时间。系统会经常的中止空进程, 从而达到调节程序缓存和系统缓存的平衡。
Activity生命周期 Activity生命周期 Activity生命周期指Activity从启动到销毁的过程 Android对Activity类的说明文档,详细介绍了Activity生命周期
Activity生命周期 Activity的主要事件回调函数 说明: 2.这些事件回调函数是Android操作系统调用的,非我们写代码调用的
Activity生命周期回调函数的调用顺序 onCreat() 初始化 onStart() 可见 onResume() 获得焦点 函数 调用时间及作用 onCreate Called when the activity is first created. 初始化,如设置布局、按钮绑定事件 onStart Called when the activity is becoming visible to the user. onResume Called when the activity will start interacting with the user.
Activity生命周期回调函数的调用顺序 从第一个Activity启动第二个Activity FirstActivity onPause() 失去焦点 SecondActivity onCreate() 初始化 onStart() 可见 onResume() 获得焦点 onStop() 不可见 函数 调用时间 onPause() Called when the system is about to start another activity,保存数据 onStop() Called when the activity is no longer visible to the user, because another activity has been resumed and is covering this one.
Activity生命周期回调函数的调用顺序 点击模拟器的back按钮回到第一个Activity SecondActivity onPause() 失焦 FirstActivity onRestart() 重新可见 onStart() 可见 onResume() 获得焦点 onStop() 不可见 onDestroy() 销毁 函数 调用时间 onRestart() Called after your activity has been stopped, prior to it being started again. onDestroy() The final call you receive before your activity is destroyed. (1)当程序主动调用finish()函数;(2)系统资源不够用时,程序被Android系统终结
Activity生命周期分类 Activity的生命周期可分为全生命周期、可视生命周期和活动生命周期 每种生命周期中包含不同的事件回调函数 onResume onStart onCreate onDestroy onPause onStop 可视生命周期 onRestart 活动生命周期 全生命周期
Activity栈 Activity生命周期 Activity表现为四种状态 Activity 四种状态 所处界面的位置 是否能被用户看到 是否能与用户交互 活动状态 最上层 完全能够 是 暂停状态 部分遮挡,不再处于界面最上层 部分能够 否 停止状态 全部遮挡 非活动状态 不在以上三种状态中的Activity则处于非活动状态
Activity栈 Activity栈:后进先出原则
Activity栈的过程(一) 应用程序启动之后,运行第一个Activity之后,FirstActivity对象就被压入栈中
Activity栈的过程(二) 当点击FirstActivity的按钮之后即启动第二个Activity,SecondActivity对象就被压入栈中 注意 手机永远显示的是栈顶部的组件界面 SecondActivity对象 FirstActivity对象
Activity栈的过程(三) 当点击第二个Activity的按钮之后即启动第三个Activity,ThirdActivity对象就被压入栈中 注意 手机永远显示的是栈顶部的组件界面 ThirdActivity对象 SecondActivity对象 FirstActivity对象
Activity栈的过程(四) 当点击第三个Activity的按钮之后即启动第四个Activity,SMSActivity对象就被压入栈中 注意 其他三个对象并没有被销毁,他们还在栈中存在 SMS Activity对象 ThirdActivity对象 SecondActivity对象 FirstActivity对象
Activity栈的过程(五) 当点击模拟器的back按钮后,因SMS Activity最后一个被加入, 所以SMSActivity对象就被第一个弹出栈。 ThirdActivity即变成当前的Activity,遵循栈的后进先出的原则 SMS Activity对象 ThirdActivity对象 SecondActivity对象 FirstActivity对象
Activity栈的过程(六) 再点击模拟器的back按钮后,ThirdActivity即被弹出。 SecondActivity即变成当前的Activity,遵循栈的后进先出的原则 ThirdActivity对象 SecondActivity对象 FirstActivity对象
Activity栈的过程(七) 再点击模拟器的back按钮后,SecondActivityActivity即被弹出。 FirstActivity即变成当前的Activity,遵循栈的后进先出的原则 SecondActivity对象 FirstActivity对象
Activity栈 Activity栈的价值——Task Activity栈的注意事项 Android帮助文档: All the Activities in a task move together as a unit. 在同一个task中的Activity被组织成同一个单元。 对用户来讲,他可能会认为我们这些Activity处于同一个应用程序,用起来就会更加的方便,用户体验更好 Activity栈的注意事项 当我们点击SecondActivity按钮之后呢,我们启动ThirdActivity,但是同时如果SecondActivity调用了finish,它就被销毁了,此时栈里面就没有了SecondActivity了。 在整个的栈中,这个Activity只有弹出和压入,是不能够重新排序的,比如说我想把第二个和第三个调换一下位置,这是不允许的,这个在Android文档里面说的非常清楚。
Activity四种启动模式 启动模式 启动模式的设置方式 standard 标准模式 singleTop singleTask singleInstance 启动模式的设置方式 Android.manifest.xml <activity android:launchMode=“”></activity> Intent.addFlags() intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 核心的IntentFlag有: FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_RESET_TASK_IF_NEEDED FLAG_ACTIVITY_SINGLE_TOP
Activity四种加载模式举例 前提:现有Task栈的元素为A-B-C-D(D在栈顶) 给D发送一个Intent,如果D的启动方式设置如下,写出task栈的元素 standard singleTop singleTask singleInstance 给B发送一个Intent,如果B的启动方式设置如下,写出task栈的元素
Android应用程序的调试 打开方式: LogCat Window → Show View → Other Android系统提供了两种调试工具LogCat和DevTools,用于定位、分析及修复程序中出现的错误 LogCat LogCat是用来获取系统日志信息的工具,并可以显示在Eclipse集成开发环境中 打开方式: Window → Show View → Other 打开Show View的选择菜单,然后在Andoird → LogCat中选择LogCat
Android应用程序的调试 Logcat LogCat的右上方的五个字母表示五种不同类型的日志信息 ,级别依次增高 [V]:详细(Verbose)信息 [D]:调试(Debug)信息 [I]:通告(Info)信息 [W]:警告(Warn)信息 [E] :错误(Error)信息 LogCat提供了“过滤”功能 在右上角的“+”号和“-”号,分别是添加和删除过滤器。用户可以根据日志信息的标签(Tag)、产生日志的进程编号(Pid)或信息等级(Level),对显示的日志内容进行过滤
Android应用程序的调试 Lagcat的使用方法 package edu.hrbeu.LogCat; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class LogCatActivity extends Activity { final static String TAG = "LOGCAT"; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.v(TAG,"Verbose"); Log.d(TAG,"Debug"); Log.i(TAG,"Info"); Log.w(TAG,"Warn"); Log.e(TAG,"Error"); }
Android应用程序的调试 DevTools DevTools是用于调试和测试的工具 包括了一系列用户各种用途的小工具:Development Settings、Exception Browser、Google Login Service、Instrumentation、Media Scanner、Package Browser、Pointer Location、Raw Image Viewer、Running processes和Terminal Emulator
Android应用程序的调试 DevTools的使用界面
本讲内容回顾 Android应用程序结构 Android 应用程序生命周期 Activity生命周期中回调函数的调用及Activity栈
作业与实验 作业: (1) Activity生命周期有多少种状态,写出类继承Activity,并完整写出其所有生命周期方法,以System.println方式输出相关信息。 (2) 简述Activity事件回调函数的作用和调用顺序。 实验 (1) Android开发环境搭建 (2) Android生命周期