文档章节

Activity 的 失去焦点 到销毁

SuShine
 SuShine
发布于 2015/06/24 13:54
字数 2101
阅读 22
收藏 0
点赞 0
评论 0

 当我们按下键盘上的Back键时,当前激活的Activity窗口就会被失去焦点,但是这时候它还没有被销毁,它的状态被设置为Stopped;当新的Activity窗口即将要显示时,它会通知WindowManagerService,这时候WindowManagerService就会处理当前处理Stopped状态的Activity窗口了,要执行的操作就是销毁它们了,在销毁的时候,就会注销它们之前所注册的键盘消息接收通道。

        新的Activity窗口通知WindowManagerService它即将要显示的过程比较复杂,但是它与我们本节要介绍的内容不是很相关,因此,这里就略过大部过程了,我们从ActvitiyRecord的windowsVisible函数开始分析。注意,这里的ActivityRecord是新的Activity窗口在ActivityManangerService的代表,而那些处于Stopped状态的Activity窗口

会放在ActivityStack类的一个等待可见的mWaitingVisibleActivities列表里面,事实于,对于那些Stopped状态的Activity窗口来说,它们是等待销毁,而不是等待可见。

        像前面一样,我们先来看一张应用程序注销键盘消息接收通道的过程的序列图,然后根据这个序列图来详细分析互一个步骤:


点击查看大图

        Step 1. ActivityRecord.windowsVisible

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityRecord.java文件中:

[java]  view plain copy
  1. class ActivityRecord extends IApplicationToken.Stub {  
  2.     ......  
  3.     boolean nowVisible;     // is this activity's window visible?  
  4.     boolean idle;           // has the activity gone idle?  
  5.     ......  
  6.   
  7.   
  8.     public void windowsVisible() {  
  9.         synchronized(service) {  
  10.             ......  
  11.   
  12.             if (!nowVisible) {  
  13.                 nowVisible = true;  
  14.                 if (!idle) {  
  15.                     .......  
  16.                 } else {  
  17.                     // If this activity was already idle, then we now need to  
  18.                     // make sure we perform the full stop of any activities  
  19.                     // that are waiting to do so.  This is because we won't  
  20.                     // do that while they are still waiting for this one to  
  21.                     // become visible.  
  22.                     final int N = stack.mWaitingVisibleActivities.size();  
  23.                     if (N > 0) {  
  24.                         for (int i=0; i<N; i++) {  
  25.                             ActivityRecord r = (ActivityRecord)  
  26.                                 stack.mWaitingVisibleActivities.get(i);  
  27.                             r.waitingVisible = false;  
  28.                             ......  
  29.                         }  
  30.                         stack.mWaitingVisibleActivities.clear();  
  31.   
  32.                         Message msg = Message.obtain();  
  33.                         msg.what = ActivityStack.IDLE_NOW_MSG;  
  34.                         stack.mHandler.sendMessage(msg);  
  35.   
  36.                     }  
  37.                 }  
  38.                 ......  
  39.             }  
  40.         }  
  41.     }  
  42.   
  43.     ......  
  44. }  
        应用程序中的每一个Activity在ActivityManagerService都有一个代表ActivityRecord,它们以堆栈的形式组织在ActivityManaerService中的ActivityStack中。一个即将要显示,但是还没有显示的Activity,它在ActivityManagerService中的ActivityRecord的成员变量nowVisible为false,而成员变量idle为ture,表示这个即将要显示的Activity窗口处于空闲状态。因此,在上面的这个函数中,会执行下面的语句:

[java]  view plain copy
  1. final int N = stack.mWaitingVisibleActivities.size();  
  2. if (N > 0) {  
  3.     for (int i=0; i<N; i++) {  
  4.         ActivityRecord r = (ActivityRecord)  
  5.         stack.mWaitingVisibleActivities.get(i);  
  6.         r.waitingVisible = false;  
  7.         ......  
  8.     }  
  9.     stack.mWaitingVisibleActivities.clear();  
  10.   
  11.     Message msg = Message.obtain();  
  12.     msg.what = ActivityStack.IDLE_NOW_MSG;  
  13.     stack.mHandler.sendMessage(msg);  
  14.   
  15. }  
        前面我们说过,当用户按下键盘上的Back键时,当前激活的Activity记录就被放在ActivityStack对象stack的成员变量mWaitingVisibleActivities中了,这时候就要对它进行处理了。首先是将它们的Activity记录的waitingVisible设置为false,然后就把它们从ActivityStack对象stack的成员变量mWaitingVisibleActivities清空,最后向ActivityStack对象stack发送一个ActivityStack.IDLE_NOW_MSG消息。这个消息最终是由ActivityStack类的activityIdleInternal函数来处理的。

        Step 2. ActivityStack.activityIdleInternal

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

[java]  view plain copy
  1. public class ActivityStack {  
  2.     ......  
  3.   
  4.     final void activityIdleInternal(IBinder token, boolean fromTimeout,  
  5.             Configuration config) {  
  6.         ......  
  7.   
  8.         ArrayList<ActivityRecord> stops = null;  
  9.         ......  
  10.   
  11.         int NS = 0;  
  12.         ......  
  13.   
  14.         synchronized (mService) {  
  15.             ......  
  16.   
  17.             // Atomically retrieve all of the other things to do.  
  18.             stops = processStoppingActivitiesLocked(true);  
  19.             NS = stops != null ? stops.size() : 0;  
  20.             ......  
  21.         }  
  22.   
  23.         int i;  
  24.   
  25.         ......  
  26.   
  27.         // Stop any activities that are scheduled to do so but have been  
  28.         // waiting for the next one to start.  
  29.         for (i=0; i<NS; i++) {  
  30.             ActivityRecord r = (ActivityRecord)stops.get(i);  
  31.             synchronized (mService) {  
  32.                 if (r.finishing) {  
  33.                     finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);  
  34.                 } else {  
  35.                     ......  
  36.                 }  
  37.             }  
  38.         }  
  39.   
  40.         ......  
  41.     }  
  42.   
  43.     ......  
  44. }  
        这个函数首先会调用processStoppingActivitiesLocked函数把所有处于Stopped状态的Activity取回来,然后逐个分析它们,如果它们的ActivityRecord中的finishing成员变量为true,就说明这个Activity需要销毁了,于是,就调用finishCurrentActivityLocked函数来销毁它们。

        Step 3. ActivityStack.finishCurrentActivityLocked

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

[java]  view plain copy
  1. public class ActivityStack {  
  2.     ......  
  3.   
  4.     private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,  
  5.             int mode) {  
  6.         ......  
  7.   
  8.         return finishCurrentActivityLocked(r, index, mode);  
  9.     }  
  10.   
  11.     private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,  
  12.             int index, int mode) {  
  13.         ......  
  14.   
  15.         // make sure the record is cleaned out of other places.  
  16.         mStoppingActivities.remove(r);  
  17.         mWaitingVisibleActivities.remove(r);  
  18.         ......  
  19.   
  20.         final ActivityState prevState = r.state;  
  21.         r.state = ActivityState.FINISHING;  
  22.   
  23.         if (mode == FINISH_IMMEDIATELY  
  24.             || prevState == ActivityState.STOPPED  
  25.             || prevState == ActivityState.INITIALIZING) {  
  26.             // If this activity is already stopped, we can just finish  
  27.             // it right now.  
  28.             return destroyActivityLocked(r, true) ? null : r;  
  29.         } else {  
  30.             ......  
  31.         }  
  32.   
  33.         return r;  
  34.     }  
  35.   
  36.     ......  
  37. }  
        从上面的Step 2中传进来的参数mode为FINISH_IMMEDIATELY,并且这个即将要被销毁的Activity的状态为Stopped,因此,接下来就会调用destroyActivityLocked函数来销毁它。

        Step 4. ActivityStack.destroyActivityLocked

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

[java]  view plain copy
  1. public class ActivityStack {  
  2.     ......  
  3.   
  4.     final boolean destroyActivityLocked(ActivityRecord r,  
  5.             boolean removeFromApp) {  
  6.         ......  
  7.   
  8.         boolean removedFromHistory = false;  
  9.   
  10.         ......  
  11.   
  12.         final boolean hadApp = r.app != null;  
  13.   
  14.         if (hadApp) {  
  15.             ......  
  16.   
  17.             try {  
  18.                 ......  
  19.                 r.app.thread.scheduleDestroyActivity(r, r.finishing,  
  20.                     r.configChangeFlags);  
  21.             } catch (Exception e) {  
  22.                 ......  
  23.             }  
  24.   
  25.             ......  
  26.         } else {  
  27.             ......  
  28.         }  
  29.   
  30.         ......  
  31.   
  32.         return removedFromHistory;  
  33.     }  
  34.   
  35.     ......  
  36. }  
         在前面一篇文章 Android应用程序启动过程源代码分析 中,我们说到,每一个应用程序进程在ActivityManagerService中,都ProcessRecord记录与之对应,而每一个Activity,都是运行在一个进程上下文中,因此,在ActivityManagerService中,每一个ActivityRecord的app成员变量都应该指向一个ProcessRecord记录,于是,这里得到的hadApp为true。在ProcessRecord类中,有一个成员变量thread,它的类型为IApplicationThread。在文章 Android应用程序启动过程源代码分析 中,我们也曾经说过,每一个应用程序在启动的时候,它都会在内部创建一个ActivityThread对象,而在这个ActivityThread对象中,有一个成员变量mAppThread,它的类型为ApplicationThread,这是一个Binder对象,专门用来负责在应用程序和ActivityManagerService之间执行进程间通信工作的。应用程序在启动的时候,就会将这个Binder对象传递给ActivityManagerService,而ActivityManagerService就会把它保存在相应的ProcessRecord记录的thread成员变量中。因此,ProcessRecord记录的thread成员变量其实就是ApplicationThread对象的远程接口,于是,执行下面这个语句的时候:

[java]  view plain copy
  1. r.app.thread.scheduleDestroyActivity(r, r.finishing,  
  2.     r.configChangeFlags);  
        就会进入到ApplicationThread类中的scheduleDestroyActivity函数来。

        Step 5. ApplicationThread.scheduleDestroyActivity

        这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

[java]  view plain copy
  1. public final class ActivityThread {  
  2.     ......  
  3.   
  4.     private final class ApplicationThread extends ApplicationThreadNative {  
  5.         ......  
  6.   
  7.         public final void scheduleDestroyActivity(IBinder token, boolean finishing,  
  8.                 int configChanges) {  
  9.   
  10.             queueOrSendMessage(H.DESTROY_ACTIVITY, token, finishing ? 1 : 0,  
  11.                     configChanges);  
  12.         }  
  13.   
  14.         ......  
  15.     }  
  16.   
  17.     ......  
  18. }  
        这个函数调用外部类ActivityThread的queueOrSendMessage函数来往应用程序的消息队列中发送一个H.DESTROY_ACTIVITY消息,这个消息最终由ActivityThread类的handleDestroyActivity函数来处理。

        Step 6. ActivityThread.handleDestroyActivity

        这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

[java]  view plain copy
  1. public final class ActivityThread {  
  2.     ......  
  3.   
  4.     private final void handleDestroyActivity(IBinder token, boolean finishing,  
  5.             int configChanges, boolean getNonConfigInstance) {  
  6.         ......  
  7.   
  8.         ActivityClientRecord r = performDestroyActivity(token, finishing,  
  9.             configChanges, getNonConfigInstance);  
  10.         if (r != null) {  
  11.             WindowManager wm = r.activity.getWindowManager();  
  12.             View v = r.activity.mDecor;  
  13.             if (v != null) {  
  14.                 ......  
  15.   
  16.                 if (r.activity.mWindowAdded) {  
  17.                     wm.removeViewImmediate(v);  
  18.                 }  
  19.                   
  20.                 ......  
  21.             }  
  22.             ......  
  23.         }  
  24.   
  25.         ......  
  26.     }  
  27.   
  28.     ......  
  29. }  
        这里首先调用performDestroyActivity来执行一些销毁Activity的操作,期间就会调用Activity的onDestroy函数让Activity本身有机会执行一些销毁前的工作了。这里通过r.activity.getWindowManager函数返回的是一个LocalWindowManager对象,而通过r.activity.mDecor得到的是一个DecorView对象,这些都是在Activity启动的时候设置好的。函数最后调用LocalWindowManager对象wm的removeViewImmediate函员来从LocalWindowManager移除这个DecorView对象。

        Step 7. LocalWindowManager.removeViewImmediate

        这个函数定义在frameworks/base/core/java/android/view/Window.java文件中:

[java]  view plain copy
  1. public abstract class Window {  
  2.     ......  
  3.   
  4.     private class LocalWindowManager implements WindowManager {  
  5.         ......  
  6.   
  7.         public final void removeViewImmediate(View view) {  
  8.             mWindowManager.removeViewImmediate(view);  
  9.         }  
  10.   
  11.         ......  
  12.   
  13.         private final WindowManager mWindowManager;  
  14.     }  
  15.   
  16.     ......  
  17. }  
        LocalWindowManager类的成员变量mWindowManager是一个WndowManagerImpl对象,这个函数只是简单地调用WndowManagerImpl类的removeViewImmediate来进一步处理。

       Step 8. WndowManagerImpl.removeViewImmediate

       这个函数定义在frameworks/base/core/java/android/view/WindowManagerImpl.java文件中:

[java]  view plain copy
  1. public class WindowManagerImpl implements WindowManager {  
  2.     ......  
  3.   
  4.     public void removeViewImmediate(View view) {  
  5.         synchronized (this) {  
  6.             int index = findViewLocked(view, true);  
  7.             ViewRoot root = mRoots[index];  
  8.             ......  
  9.   
  10.             root.die(true);  
  11.               
  12.             ......  
  13.         }  
  14.     }  
  15.   
  16.     ......  
  17. }  
         这个函数首先是找到这个view所属的ViewRoot对象root,然后调用这个root对象的die函数来销毁它。

         Step 9. ViewRoot.die

         这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:

[java]  view plain copy
  1. public final class ViewRoot extends Handler implements ViewParent,  
  2.         View.AttachInfo.Callbacks {  
  3.     ......  
  4.   
  5.     public void die(boolean immediate) {  
  6.         if (immediate) {  
  7.             doDie();  
  8.         } else {  
  9.             ......  
  10.         }  
  11.     }  
  12.       
  13.     ......  
  14. }  
        上面Step 8传进来的immediate参数为true,因此,这里直接调用doDie函数来进一步处理。

        Step 10. ViewRoot.doDie

        这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:

[java]  view plain copy
  1. public final class ViewRoot extends Handler implements ViewParent,  
  2.         View.AttachInfo.Callbacks {  
  3.     ......  
  4.   
  5.     void doDie() {  
  6.         ......  
  7.   
  8.         synchronized (this) {  
  9.             ......  
  10.   
  11.             if (mAdded) {  
  12.                 mAdded = false;  
  13.                 dispatchDetachedFromWindow();  
  14.             }  
  15.         }  
  16.     }  
  17.       
  18.     ......  
  19. }  
        当我们把Activity窗口中的View添加到一个ViewRoot对象时,就会把它的成员变量mAdded设置为true,这样就表示这个ViewRoot中有View存在,于是,这里就会调用dispatchDetachedFromWindow函数来进一步处理。

        Step 11. ViewRoot.ispatchDetachedFromWindow

        这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:

[java]  view plain copy
  1. public final class ViewRoot extends Handler implements ViewParent,  
  2.         View.AttachInfo.Callbacks {  
  3.     ......  
  4.   
  5.     void dispatchDetachedFromWindow() {  
  6.         ......  
  7.   
  8.         if (mInputChannel != null) {  
  9.             if (mInputQueueCallback != null) {  
  10.                 ......  
  11.             } else {  
  12.                 InputQueue.unregisterInputChannel(mInputChannel);  
  13.             }  
  14.         }  
  15.   
  16.         try {  
  17.             sWindowSession.remove(mWindow);  
  18.         } catch (RemoteException e) {  
  19.         }  
  20.   
  21.         ......  
  22.     }  
  23.   
  24.     ......  
  25. }  

本文转载自:http://blog.csdn.net/sfshine/article/details/9118191

共有 人打赏支持
SuShine
粉丝 118
博文 435
码字总数 88625
作品 0
青岛
后端工程师
Android生命周期——认识Activity

1、什么是Activity? Activity是一个应用程序组件,提供用户与程序交互的界面。 2、Activity如何创建使用: 继承Android的Activity类 重写方法 设置显示布局 在AndroidManifest文件中,注册A...

落叶-归根 ⋅ 2016/07/23 ⋅ 0

Android7.0 分屏下 Activity 与 Fragment 生命周期(一)

小菜前段时间整理了一篇关于我们真的了解 Activity 与 Fragment 的生命周期吗?的小博文,整理了基础版的关于 Activity 与 Fragment 的生命周期。 后来又一次被一个大大神问到在 Android7.0...

阿策神奇 ⋅ 06/11 ⋅ 0

Android生命周期

Activity生命周期: onCreate() :Activity创建时调用,有且只调用一次 onStart() : 紧跟onCreate()之后调用,目标是视图可见 onResume() : 在onStart()之后调用,目标是使视图控件获得焦点 ...

狼行千年 ⋅ 2015/05/17 ⋅ 0

快速掌握activity的生命周期

activity的生命周期不管是在面试还是在工作中我们都会经常遇到,这当然也是非常基础的,基础也很重要哦,学会activity的生命周期对我们以后开发更健壮的程序会有很大帮助。下面来看一下Activ...

晨曦之光 ⋅ 2012/03/13 ⋅ 0

Android 解读开源项目UniversalMusicPlayer(播放控制层)

版权声明:本文为博主原创文章,未经博主允许不得转载 源码:AnliaLee/android-UniversalMusicPlayer 首发地址:Anlia_掘金 大家要是看到有错误的地方或者有啥好的建议,欢迎留言评论 前言 ...

Anlia ⋅ 04/29 ⋅ 0

03_Activity 生命周期介绍【图解】

一、基本概念 Activity 负责创建一个窗口,程序员可以通过 setContentView(View)向这个窗口添加一些 UI组件。本文将介绍 Activiy 的生命周期,并且展示一个小程序来验证 Activity 的执行过程...

晨曦之光 ⋅ 2012/03/14 ⋅ 0

android TV 通过按键控制RecyclerView中的item的选中,移动,点击功能

前言 android tv开发中常常会用到recyclerview展示内容,并且要处理好按键控制item的选中,移动,点击功能,会遇到失去焦点,recyclerview 获取childView获取不到,出现null的问题。下面介绍...

MRYangY ⋅ 03/06 ⋅ 0

Android 面试技能树梳理

相信大家都有面试的经历,相对比面试官的问的一些问题其实都是基础的知识,但就是一些基础的知识我们也不是很完美的回答出来,我们也知道现在的开发人员很多,一家公司一个岗位就会有很多的开...

liu3364575 ⋅ 05/05 ⋅ 0

移动端解决input获取焦点软键盘弹出影响定位的问题

这是刚做前端时候写的文章,拿到简书上做记录吧!以免以后再遇到这样的坑。 在最近的一次H5页面开发中,发现在安卓端点击输入框的时候虚拟键盘会把最下边的‘保存’按钮顶上去。 在试了很多方...

愿爱无忧dk_ ⋅ 05/25 ⋅ 0

input 输入框被软键盘遮挡问题

1.安卓手机 在软键盘被弹起来的时候输入框不被遮挡,支持性良好 2.ios手机 在软键盘被弹起来的时候输入框被遮挡,体验很不好 在经过多次实验发现,ios手机输入框被弹起的瞬间是不被遮挡的,过...

爱喝水的小熊 ⋅ 06/06 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

005. 深入JVM学习—Java堆内存参数调整

1. JVM整体内存调整图解(调优关键) 实际上每一块子内存区域都会存在一部分可变伸缩区域,其基本流程:如果内存空间不足,则在可变的范围之内扩大内存空间,当一段时间之后,内存空间不紧张...

影狼 ⋅ 10分钟前 ⋅ 0

内存障碍: 软件黑客的硬件视图

此文为笔者近日有幸看到的一则关于计算机底层内存障碍的学术论文,并翻译(机译)而来[自认为翻译的还行],若读者想要英文原版的论文话,给我留言,我发给你。 内存障碍: 软件黑客的硬件视图...

Romane ⋅ 43分钟前 ⋅ 0

SpringCloud 微服务 (七) 服务通信 Feign

壹 继续第(六)篇RestTemplate篇 做到现在,本机上已经有注册中心: eureka, 服务:client、order、product 继续在order中实现通信向product服务,使用Feign方式 下面记录学习和遇到的问题 贰 or...

___大侠 ⋅ 今天 ⋅ 0

gitee、github上issue标签方案

目录 [TOC] issue生命周期 st=>start: 开始e=>end: 结束op0=>operation: 新建issueop1=>operation: 评审issueop2=>operation: 任务负责人执行任务cond1=>condition: 是否通过?op3=>o......

lovewinner ⋅ 今天 ⋅ 0

浅谈mysql的索引设计原则以及常见索引的区别

索引定义:是一个单独的,存储在磁盘上的数据库结构,其包含着对数据表里所有记录的引用指针. 数据库索引的设计原则: 为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索...

屌丝男神 ⋅ 今天 ⋅ 0

String,StringBuilder,StringBuffer三者的区别

这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面。 首先说运行速度,或者说是, 1.执行速度 在这方面运行速度快慢为:StringBuilder(线程不安全,可变) > StringBuffer...

时刻在奔跑 ⋅ 今天 ⋅ 0

java以太坊开发 - web3j使用钱包进行转账

首先载入钱包,然后利用账户凭证操作受控交易Transfer进行转账: Web3j web3 = Web3j.build(new HttpService()); // defaults to http://localhost:8545/Credentials credentials = Wallet......

以太坊教程 ⋅ 今天 ⋅ 0

Oracle全文检索配置与实践

Oracle全文检索配置与实践

微小宝 ⋅ 今天 ⋅ 0

mysql的分区和分表

1,什么是mysql分表,分区 什么是分表,从表面意思上看呢,就是把一张表分成N多个小表,具体请看mysql分表的3种方法 什么是分区,分区呢就是把一张表的数据分成N多个区块,这些区块可以在同一...

梦梦阁 ⋅ 今天 ⋅ 0

exception.ZuulException: Forwarding error

错误日志 com.netflix.zuul.exception.ZuulException: Forwarding error Caused by: com.netflix.hystrix.exception.HystrixRuntimeException: xxx timed-out and no fallback available. Ca......

jack_peng ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部