Activity- 的 -36- 大难点,你会几个?,android 游戏开发实践指南
1.8 Activity 的四种状态
 
 - runnig:用户可以点击,- activity处于栈顶状态。
- paused:- activity失去焦点的时候,被一个非全屏的- activity占据或者被一个透明的- activity覆盖,这个状态的- activity并没有销毁,它所有的状态信息和成员变量仍然存在,只是不能够被点击。(内存紧张的情况,这个- activity有可能被回收)
 
 - stopped:这个- activity被另外一个- activity完全覆盖,但是这个- activity的所有状态信息和成员变量仍然存在(除了内存紧张)
- killed:这个- activity已经被销毁,其所有的状态信息和成员变量已经不存在了。
1.9 如何处理异常退出
 
 - Activity异常退出的时候 -->- onPause()-->- onSaveInstanceState()-->- onStop()-->- onDestory()
- 需要注意的是 - onSaveInstanceState()方法与- onPause并没有严格的先后关系,有可能在- onPause之前,也有可能在其后面调用,但会在- onStop()方法之前调用
- 异常退出后又重新启动该 - Activity-->- onCreate()-->- onStart()-->- onRestoreInstanceState()-->- onResume()
 
 - 搞懂这个生命周期的执行后就可以回答了,首先要知道面试官的意思:是要重新启动并恢复这个 - Activity还是说直接退出整个- app
- 如果要恢复则要在 - onSaveInstanceState()中进行保存数据并在- onRestoreInstanceState()中进行恢复
- 如果是要退出 - app的话就要捕获全局的异常信息,并退出- app
- 当然个人建议是使用 - UncaughtExceotionHandler来捕获全局异常进行退出- app的操作,这样会减少之前崩溃所造成的后遗症!
1.10 什么是 onNewIntent
 
 - 如果 - IntentActivity处于任务栈的顶端,也就是说之前打开过的- Activity,现在处于- onPause、- onStop状态的话,其他应用再发送- Intent的话
- 执行顺序为: - onNewIntent,- onRestart,- onStart,- onResume。
二、 启动模式
2.1 启动模式
 
 - Activity一共有四种- launchMode:- standard、- singleTop、- singleTask、- singleInstance。
 
 - Standard模式(默认模式)
- 说明: 每次启动一个 - Activity都会又一次创建一个新的实例入栈,无论这个实例是否存在。
- 生命周期:每次被创建的实例 - Activity的生命周期符合典型情况,它的- onCreate、- onStart、- onResume都会被调用。
- 举例:此时 - Activity栈中以此有- A、- B、- C三个- Activity,此时 C 处于栈顶,启动模式为- Standard模式。若在- C Activity中加入点击事件,须要跳转到还有一个同类型的- C Activity。结果是还有一个- C Activity进入栈中,成为栈顶。
 
 - SingleTop模式(栈顶复用模式)
- 说明:分两种处理情况:须要创建的 - Activity已经处于栈顶时,此时会直接复用栈顶的- Activity。不会再创建新的- Activity;若须要创建的- Activity不处于栈顶,此时会又一次创建一个新的- Activity入栈,同- Standard模式一样。
- 生命周期:若情况一中栈顶的 - Activity被直接复用时,它的- onCreate、- onStart不会被系统调用,由于它并没有发生改变。可是一个新的方法- onNewIntent会被回调(- Activity被正常创建时不会回调此方法)。
- 举例:此时 - Activity栈中以此有- A、- B、- C三个- Activity,此时- C处于栈顶,启动模式为- SingleTop模式。情况一:在- C Activity中加入点击事件,须要跳转到还有一个同类型的- C Activity。结果是直接复用栈顶的- C Activity。情况二:在- C Activity中加入点击事件,须要跳转到还有一个- A Activity。结果是创建一个新的- Activity入栈。成为栈顶。
 
 - SingleTask模式(栈内复用模式)
- 说明:若须要创建的 - Activity已经处于栈中时,此时不会创建新的- Activity,而是将存在栈中的- Activity上面的其他- Activity所有销毁,使它成为栈顶。
- 如果是在别的应用程序中启动它,则会新建一个 - task,并在该 task 中启动这个- Activity,- singleTask允许别的- Activity与其在一个- task中共存,也就是说,如果我在这个- singleTask的实例中再打开新的- Activity,这个新的- Activity还是会在- singleTask的实例的- task中。
- 生命周期:同 - SingleTop模式中的情况一同样。仅仅会又一次回调- Activity中的- onNewIntent方法
- 举例:此时 - Activity栈中以此有- A、- B、- C三个- Activity。此时- C处于栈顶,启动模式为- SingleTask模式。情况一:在- C Activity中加入点击事件,须要跳转到还有一个同类型的- C Activity。结果是直接用栈顶的- C Activity。情况二:在- C Activity中加入点击事件,须要跳转到还有一个- A Activity。结果是将- A Activity上面的- B、- C所有销毁,使- A Activity成为栈顶。
 
 - SingleInstance模式(单实例模式)
- 说明: - SingleInstance比较特殊,是全局单例模式,是一种加强的- SingleTask模式。它除了具有它所有特性外,还加强了一点:只有一个实例,并且这个实例独立运行在一个- task中,这个- task只有这个实例,不允许有别的- Activity存在。
- 这个经常使用于系统中的应用,比如 - Launch、锁屏键的应用等等,整个系统中仅仅有一个!所以在我们的应用中一般不会用到。了解就可以。
- 举例:比方 - A Activity是该模式,启动- A后。系统会为它创建一个单独的任务栈,由于栈内复用的特性。兴许的请求均不会创建新的- Activity,除非这个独特的任务栈被系统销毁。
2.2 启动模式的使用方式
 
 - 在 - Manifest.xml中指定- Activity启动模式
- 一种静态的指定方法 
- 在 - Manifest.xml文件里声明- Activity的同一时候指定它的启动模式
- 这样在代码中跳转时会依照指定的模式来创建 - Activity。
- 启动 - Activity时。在- Intent中指定启动模式去创建- Activity
- 一种动态的启动模式 
- 在 - new一个- Intent后
- 通过 - Intent的- addFlags方法去动态指定一个启动模式。
- 注意:以上两种方式都能够为 - Activity指定启动模式,可是二者还是有差别的。
- 优先级:动态指定方式即另外一种比第一种优先级要高,若两者同一时候存在,以另外一种方式为准。 
- 限定范围:第一种方式无法为 - Activity直接指定- FLAG_ACTIVITY_CLEAR_TOP标识,另外一种方式无法为- Activity指定- singleInstance模式。
2.3 启动模式的实际应用场景
这四种模式中的
Standard模式是最普通的一种,没有什么特别注意。而SingleInstance模式是整个系统的单例模式,在我们的应用中一般不会应用到。所以,这里就具体解说SingleTop和SingleTask模式的运用场景:
 
 - SingleTask模式的运用场景
- 最常见的应用场景就是保持我们应用开启后仅仅有一个 - Activity的实例。
- 最典型的样例就是应用中展示的主页( - Home页)。
- 假设用户在主页跳转到其他页面,运行多次操作后想返回到主页,假设不使用 - SingleTask模式,在点击返回的过程中会多次看到主页,这明显就是设计不合理了。
- SingleTop模式的运用场景
- 假设你在当前的 - Activity中又要启动同类型的- Activity
- 此时建议将此类型 - Activity的启动模式指定为- SingleTop,能够降低 Activity 的创建,节省内存!
- 注意:复用 - Activity时的生命周期回调
- 这里还须要考虑一个 - Activity跳转时携带页面參数的问题。
- 由于当一个 - Activity设置了- SingleTop或者- SingleTask模式后,跳转此- Activity出现复用原有- Activity的情况时,此- Activity的- onCreate方法将不会再次运行。- onCreate方法仅仅会在第一次创建- Activity时被运行。
- 而一般 - onCreate方法中会进行该页面的数据初始化、- UI初始化,假设页面的展示数据无关页面跳转传递的參数,则不必操心此问题
- 若页面展示的数据就是通过 - getInten()方法来获取,那么问题就会出现:- getInten()获取的一直都是老数据,根本无法接收跳转时传送的新数据!
- 以下,通过一个样例来具体解释: 
 
 - 以上代码中的 - CourseDetailActivity在配置文件里设置了启动模式是- SingleTop模式,依据上面启动模式的介绍可得知,当- CourseDetailActivity处于栈顶时。
- 再次跳转页面到 - CourseDetailActivity时会直接复用原有的- Activity,并且此页面须要展示的数据是从- getIntent()方法得来,可是- initData()方法不会再次被调用,此时页面就无法显示新的数据。
- 当然这样的情况系统早就为我们想过了,这时我们须要另外一个回调 - onNewIntent(Intent intent)方法。此方法会传入最新的- intent,这样我们就能够解决上述问题。这里建议的方法是又一次去- setIntent。然后又一次去初始化数据和- UI。代码例如以下所看到的:
 
 - 这样,在一个页面中能够反复跳转并显示不同的内容。 
2.4 快速启动一个 Activity
 
 - 这个问题其实也是比较简单的,就是不要在 - Activity的- onCreate方法中执行过多繁重的操作,并且在- onPasue方法中同样不能做过多的耗时操作。
2.5 启动流程
- 注意!这里并不是要回答 - Activity的生命周期!
2.6 Activity 的 Flags
 
 - 标记位既能够设定 Activity 的启动模式,如同上面介绍的,在动态指定启动模式,比方 - FLAG_ACTIVITY_NEW_TASK和- FLAG_ACTIVITY_SINGLE_TOP等。它还能够影响- Activity的运行状态 ,比方- FLAG_ACTIVITY_CLEAN_TOP和- FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS等。
- 以下介绍几个基本的标记位,切勿死记,理解几个就可以,须要时再查官方文档。 
 
 - FLAG_ACTIVITY_NEW_TASK
- 作用是为 - Activity指定- “SingleTask”启动模式。跟在- AndroidMainfest.xml指定效果同样
- FLAG_ACTIVITY_SINGLE_TOP
- 作用是为 - Activity指定- “SingleTop”启动模式,跟在- AndroidMainfest.xml指定效果同样。
- FLAG_ACTIVITY_CLEAN_TOP
- 具有此标记位的 - Activity,启动时会将与该- Activity在同一任务栈的其他- Activity出栈。
- 一般与 - SingleTask启动模式一起出现。
- 它会完毕 - SingleTask的作用。
- 但事实上 - SingleTask启动模式默认具有此标记位的作用
- FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- 具有此标记位的 - Activity不会出如今历史- Activity的列表中
- 使用场景:当某些情况下我们不希望用户通过历史列表回到 - Activity时,此标记位便体现了它的效果。
- 它等同于在 - xml中指定- Activity的属性.
2.7 onNewInstent()方法什么时候执行
 
 这个是启动模式中的了,当此 Activity 的实例已经存在,并且此时的启动模式为 SingleTask 和 SingleInstance ,另外当这个实例位于栈顶且启动模式为 SingleTop 时也会触发 onNewInstent() 。
三、 数据
3.1 Activity 间通过 Intent 传递数据大小限制
 
 - Intent在传递数据时是有大小限制的,这里官方并未详细说明,不过通过实验的方法可以测出数据应该被限制在- 1MB之内(- 1024KB)
- 我们采用传递 - Bitmap的方法,发现当图片大小超过- 1024(准确地说是- 1020左右)的时候,程序就会出现闪退、停止运行等异常(不同的手机反应不同)
- 因此可以判断 - Intent的传输容量在- 1MB之内。
3.2 内存不足时系统会杀掉后台的 Activity,若需要进行一些临时状态的保存,在哪个方法进行
 
 - Activity的- onSaveInstanceState()和- onRestoreInstanceState()并不是生命周期方法,它们不同于- onCreate()、- onPause()等生命周期方法,它们并不一定会被触发。
- onSaveInstanceState()方法,当应用遇到意外情况(如:内存不足、用户直接按- Home键)由系统销毁一个- Activity,- onSaveInstanceState()会被调用。
- 但是当用户主动去销毁一个 - Activity时,例如在应用中按返回键,- onSaveInstanceState()就不会被调用。
- 除非该 - activity不是被用户主动销毁的,通常- onSaveInstanceState()只适合用于保存一些临时性的状态,而- onPause()适合用于数据的持久化保存。
3.3 onSaveInstanceState() 被执行的场景
 
 - 系统不知道你按下 - HOME后要运行多少其他的程序,自然也不知道- activity A是否会被销毁
- 因此系统都会调用 - onSaveInstanceState(),让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则:
- 当用户按下 - HOME键时
- 长按 - HOME键,选择运行其他的程序时
- 锁屏时 
- 从 - activity A中启动一个新的- activity时
- 屏幕方向切换时 
3.4 两个 Activity 之间跳转时必然会执行的方法
 
 一般情况下比如说有两个 activity , 分别叫 A , B ,当在 A 里面激活 B 组件的时候, A 会调用 onPause() 方法,然后 B 调用 onCreate() , onStart() , onResume() 。
这个时候 B 覆盖了窗体, A 会调用 onStop() 方法. 如果 B 是个透明的,或者 是对话框的样式, 就不会调用 A 的 onStop() 方法。
3.5 用 Intent 去启动一个 Activity 之外的方法
 
 - 使用 - adb shell am命令
- am启动一个- activity
- adb shell am start com.example.fuchenxuan/.MainActivity
- am发送一个广播,使用- action
- adb shell am broadcast -a magcomm.action.TOUCH_LETTER
3.6 scheme 跳转协议
 
 3.6.1 定义

- 服务器可以定制化跳转 - app页面
- app可以通过- Scheme跳转到另一个- app页面
- 可以通过 - h5页面跳转- app原生页面
3.6.2 协议格式:
 
  
 - qh代表- Scheme协议名称
- test代表- Scheme作用的地址域
- 8080代表改路径的端口号
- /goods代表的是指定页面(路径)
- goodsId和- name代表传递的两个参数
3.6.3 Scheme 使用
- 定义一个 - Scheme
 
 - 获取 - Scheme跳转的参数
 
 - 调用方式 
- 原生调用 
 
 - html 调用 
 
 - 判断某个 Scheme 是否有效 
 
 - 关于 scheme 跳转协议,可以查看下面的博客,站在巨人的肩膀上,才能看得更远Android产品研发(十一)-->应用内跳转Scheme协议 
四、 Context
4.1 Context , Activity , Appliction 的区别
 
 - 相同: - Activity和- Application都是- Context的子类。
- Context从字面上理解就是上下文的意思, 在实际应用中它也确实是起到了管理 上下文环境中各个参数和变量的总用, 方便我们可以简单的访问到各种资源。
- 不同:维护的生命周期不同。 - Context维护的是当前的- Activity的生命周期,- Application维护的是整个项目的生命周期。
- 使用 - context的时候, 小心内存泄露, 防止内存泄露
4.2 Context 是什么
 
 - 它描述的是一个应用程序环境的信息,即上下文。 
- 该类是一个抽象( - abstract class)类,- Android提供了该抽象类的具体实 现类(- ContextIml)。
- 通过它我们可以获取应用程序的资源和类, 也包括一些应用级别操作, 例如:启动一个 - Activity,发送广播,接受- Intent,信息,等。
4.2.1 附加一张 Context 继承关系图
[图片上传失败...(image-de33df-1572405738902)]
4.3 获取当前屏幕 Activity 的对象
 
 - 使用 ActivityLifecycleCallbacksAndroid 如何获取当前Activity实例对象? 
4.4 Activity 的管理机制
 
 - 面试官问这个问题,想看看大家对 Activity 了解是否深入: 
- 什么是 ActivityRecord 
- 什么是 TaskRecord 
- 什么是 ActivityManagerService 
4.5 什么是 Activity
 
 - 四大组件之一,通常一个用户交互界面对应一个 - activity。
- activity是- Context的子类,同时实现了- window.callback和- keyevent.callback,可以处理与窗体用户交互的事件。
- 开发中常用的有 - FragmentActivity、- ListActivity、- TabActivity(- Android 4.0被- Fragment取代)
五、 进程
5.1 Android 进程优先级
- 前台 / 可见 / 服务 / 后台 / 空 
 
 5.1.1 前台进程:Foreground process
 
 - 用户正在交互的 - Activity(- onResume())
- 当某个 - Service绑定正在交互的- Activity
- 被主动调用为前台 - Service(- startForeground())
- 组件正在执行生命周期的回调( - onCreate()、- onStart()、- onDestory())
- BroadcastReceiver正在执行- onReceive()
5.1.2 可见进程:Visible process
 
 - 我们的 - Activity处在- onPause()(没有进入- onStop())
- 绑定到前台 - Activity的- Service
5.1.3 服务进程:Service process
 
 - 简单的 - startService()启动。
5.1.4 后台进程:Background process
 
 - 对用户没有直接影响的进程 --- - Activity处于- onStop()的时候。
- android:process=":xxx"
5.1.5 空进程:Empty process
 
 - 不含有任何的活动的组件。( - Android设计的,处于缓存的目的,为了第二次启动更快,采取的一个权衡)
5.2 可见进程
 
 可见进程指部分程序界面能够被用户看见,却不在前台与用户交互的进程。例如,我们在一个界面上弹出一个对话框(该对话框是一个新的
Activity),那么在对话框后面的原界面是可见的,但是并没有与用户进行交互,那么原界面就是可见进程。
- 一个进程满足下面任何一个条件都被认为是可视的: 
- 寄宿着一个不是前台的活动,但是它对用户仍可见(它的 - onPause()方法已经被调用)。举例来说,这可能发生在,如果一个前台活动在一个对话框(其他进程的)运行之后仍然是可视的,比如输入法的弹出时。
- 寄宿着一个服务,该服务绑定到一个可视的活动。 
- 一个可视进程被认为是及其重要的且不会被杀死,除非为了保持前台进程运行。 
5.3 服务进程
 
 - 服务进程是通过 - startService()方法启动的进程,但不属于前台进程和可见进程。例如,在后台播放音乐或者在后台下载就是服务进程。
- 系统保持它们运行,除非没有足够内存来保证所有的前台进程和可视进程。 
5.4 后台进程
 
 - 后台进程是一个保持着一个当前对用户不可视的活动(已经调用 - Activity对象的- onStop()方法)(如果还有除了- UI线程外其他线程在运行话,不受影响)。
例如我正在使用
Home键让
- 这些进程没有直接影响用户体验,并且可以在任何时候被杀以收回内存用于一个前台、可视、服务进程。 
- 一般地有很多后台进程运行着,因此它们保持在一个 - LRU(- least recently used,即最近最少使用,如果您学过操作系统的话会觉得它很熟悉,跟内存的页面置换算法- LRU一样)列表以确保最近使用最多的活动的进程最后被杀。
5.5 空进程
 
 










 
    
评论