android四大组件之Activity - (1)从源码中理解并巧用onWindowFocusChanged(boolean hasFocus)

这里开始到后面,想趁着有时间,将Android四大组件和一些系统组件做一些总结和记录.由于网上已经有很多写的很好并且总结也全面的文章.小弟我也囊中羞涩不敢献丑,就记录一些自己觉得重要的有用的知识点,顺便大家一起学习讨论啥的也好

Activity作为四大组件之一,对于整个Android开发有多重要就无需赘言了.关于它的生命周期,这里借用下官网的图,便一目了然:

那么它的生命周期和我们所说的onWindowFocusChanged(boolean hasFocus)方法有何关系?

Activity生命周期源于onCreate(),于是我们将很多数据的初始化放在这里,将数据的持久保存放在onStop() onPause()和onDestroy()等方法,将临时数据的一致性保存处理放在onSaveInstanceState()等等.  那提一个问题, Activity作为装在各种布局控件的组件容器,有没有试过当我们某一个组件的宽高肯定不为0, 但是对该组件使用getWidth() getHeight() 的时候,发现获得的宽高值为0?  因为这个时候在onCreate()那里setContentView()
的视图初始化以及各个组件的测量并没有完成, 而我们就已经调用getWidth() getHeight() 这两个方法了.

追溯下源码, 会发现 Activity在初始化视图的过程中, 会调用onMeasure() onLayout() onDraw()等方法,去绘制组件,测量组件 同时刷新当前的视图,直至完成整个视图的初始化过程.我们如何在适当时候知道Activity完成视图的初始化才去使用getWidth() getHeight()? 这里有一个方法, 使用onWindowFocusChanged(boolean hasFocus);

我们通过Activity源码去查看,发现onWindowFocusChanged(boolean hasFocus)出现在window$callback 和View.java这两个类中. 而window$callback 当中所使用的该方法实际上也是来自View.java. 那么我们看看这个方法在View中是怎样的:

     /**
     * 当当前的window(窗口)获取或者失去焦点的时候会回调这个方法.请注意,这个焦点和view焦点
     * 是分离的,为了获取按键事件,view和view所在的窗口都必须获得焦点.如果一个窗口处于你的输入
     * 事件的最上层,那么该窗口将失去焦点而view的焦点会保持不变.
     * Called when the window containing this view gains or loses focus.  Note
     * that this is separate from view focus: to receive key events, both
     * your view and its window must have focus.  If a window is displayed
     * on top of yours that takes input focus, then your own window will lose
     * focus but the view focus will remain unchanged.
     *
     * @param hasWindowFocus True if the window containing this view now has
     *        focus, false otherwise.
     */
    public void onWindowFocusChanged(boolean hasWindowFocus) {
    	//获取软键盘
        InputMethodManager imm = InputMethodManager.peekInstance();
        if (!hasWindowFocus) {
            if (isPressed()) {
            	//键盘有按下事件,则强制将该view包含的所有子控件全部setPressed()设置为false
                setPressed(false);
            }
            if (imm != null && (mPrivateFlags & FOCUSED) != 0) {
            	//这是一个隐藏的方法(带@hide标签),当view失去焦点时会调用该方法
                imm.focusOut(this);
            }
            //移除长按事件回调的接口方法
            removeLongPressCallback();
            //移除轻触探测器,源码中叫 "Remove the tap detection timer."
            removeTapCallback();
            //当焦点(fucos)从按下变成取消的时候会调用,属于隐藏方法
            onFocusLost();
        } else if (imm != null && (mPrivateFlags & FOCUSED) != 0) {
            //当view获得焦点时调用该方法,属于隐藏方法
            imm.focusIn(this);
        }
        //强制view刷新drawable state,并且会回调drawableStateChanged()方法
        refreshDrawableState();
    }

源码的注释已经写上,应该看出,窗口的焦点和view的焦点是分离的, 这个方法onWindowFocusChanged(boolean hasFocus) 被回调的触发时机是窗口获取或失去焦点的时候.

那么在一个Activity新建的时候,第一次获取焦点是在哪里调用这个方法?看源码:

     /**
     * Called after {@link #onRestoreInstanceState}, {@link #onRestart}, or
     * {@link #onPause}, for your activity to start interacting with the user.
     * This is a good place to begin animations, open exclusive-access devices
     * (such as the camera), etc.
     *
     * 从下面这段官方注释中,这一段"Use {@link #onWindowFocusChanged} to know for certain that..."
     * 可知道,在onResume()方法之后会调用onWindowFocusChanged()方法~
     *
     * <p>Keep in mind that onResume is not the best indicator that your activity
     * is visible to the user; a system window such as the keyguard may be in
     * front.  Use {@link #onWindowFocusChanged} to know for certain that your
     * activity is visible to the user (for example, to resume a game).
     *
     * <p><em>Derived classes must call through to the super class's
     * implementation of this method.  If they do not, an exception will be
     * thrown.</em></p>
     *
     * @see #onRestoreInstanceState
     * @see #onRestart
     * @see #onPostResume
     * @see #onPause
     */
    protected void onResume() {
        getApplication().dispatchActivityResumed(this);
        mCalled = true;
    }

可见, 在Activity中的窗口获取焦点的时候,首次调用onWindowFocusChanged()是在onResume()方法后面.之后就会发生正常的窗口失去或重新获取焦点的事情等等.

那么让我们来想想, 哪些情况是会导致窗口失去或者获取焦点的?

1, 首次进入一个Activity后会在onResume()方法后面调用

2, 从Activity 跳到另一个Activity. 新的窗口会获取焦点, 就的Activity的窗口会失去焦点.

3, 打开软键盘进行输入,  窗口失去焦点.

4, 软键盘输入完毕消失,  窗口重新获取焦点

5, 应用后台,  窗口失去焦点

6,应用从后台返回当前, 窗口重新获取焦点

... ...

上面这些情况都会Activity都会调用onWindowFocusChanged() 方法.

好了,上面从源码理解了为什么以及何时会调用这个方法, 那么再来看看如何巧用?举个栗子:

巧用一:

当Activity来到onResume()的时候,视图已经初始化完毕了. 在文章开始的时候提到,视图初始化还没完成就调用getwidth()  getHeight()获取宽高值是为0的. 那么现在将获取宽高的方法放在onWindowFocusChanged() 中去,就会发现获得的宽高就是正确的了~

巧用二:

当应用被用户按Home键变为后台, 或者从后台中将应用变为前台时,如果要对某些数据进行保存和恢复, 也可以在这里做一些操作. 当然这并不是唯一的选择, 也可以放在onPause(), onResume()等方法中去.只是说, 当知道了onWindowFocusChanged() 的作用, 这里我们就能多一个选择,不是挺好嘛.

当然,还有其他一些用法,可以参考上面所提及的触发onWindowFocusChanged() 方法的时机.同时我们也不能为了用而用,知道多一些,理解深一些,我们才能做出更好的选择和实现.本文到此,晚安啦~

时间: 2024-10-06 12:32:01

android四大组件之Activity - (1)从源码中理解并巧用onWindowFocusChanged(boolean hasFocus)的相关文章

Android四大组件之Activity详解 &middot; yclog

Activity生命周期: onCreate:在Acitivty第一次创建时调用,用于做初始化的工作onStart:onCreate调用后调用,此次界面对用户来说无法看见onResume:此次界面可见并显示到前台,且当前Acitvity位于当前栈顶,并且处于运行状态onPause:表示当前Activity正在停止,常做一些存储数据.停止动画等工作(不做耗时操作)onStop:表示当前Activity即将停止,一般做微量级的回收工作onDestory:表示当前Activity即将被销毁,可做一些回

Android四大组件之Activity(活动)及其布局的创建与加载布局

Android四大组件之Activity(活动)及其布局的创建与加载布局 什么是Activity ? 活动(Activity)是包含用户界面的组件,主要用于和用户进行交互的,一个应用程序中可以包含零个或多个活动. 手动创建Activity的过程详解 到现在为止,你还没有手动创建过活动呢,在第一个安卓工程中,HelloWorldActivity是ADT帮我们创建的,手动创建活动可以加深我们的理解,因此现在是时候应该自己动手了. 首先,你需要再新建一个 Android 项目,项目名可以叫做 Acti

Android四大组件之——Activity的开启:StartActivity()和StartActivityForResult()(图文详解)

            如需转载请在文章开头处注明本博客网址:http://www.cnblogs.com/JohnTsai       联系方式:[email protected]       [Android四大组件学习系列Activity篇]        1.Android四大组件之——Activity(一)定义.状态和后退栈(图文详解) 2.Android四大组件之——Activity的生命周期(图文详解) 3.Android四大组件之——Activity的开启StartActivit

Android学习之路——Android四大组件之activity(二)

上一篇讲了activity的创建和启动,这一篇,我们来讲讲activity的数据传递 activity之间的数据传递,这里主要介绍的是activity之间简单数据的传递,直接用bundle传递基本数据类型的数据.还有一种数据类型是parcelable和serialable 用bundle 传递数据有两种情况,这篇文章就分别从两个方面说明一下. 一.利用bundle传递基本数据类型 1.启动时传递数据,使用intent的put方法,将数据写入bundle中,然后startActivity(inte

【Android的从零单排开发日记】之入门篇(四)——Android四大组件之Activity

在Android中,无论是开发者还是用户,接触最多的就算是Activity.它是Android中最复杂.最核心的组件.Activity组件是负责与用户进行交互的组件,它的设计理念在很多方面都和Web页面类似.当然,这种相似性主要体现在设计思想上.在具体实现方面,Android的Activity组件有自己的设计规范,同时,它能够更简便地使用线程.文件数据等本地资源. 一.Activity 的生命周期 Activity 的生命周期是被以下的函数控制的. 1 public class Activity

Android学习之路——Android四大组件之activity(一)

一.什么是Activity? Activity简单的说就是一个界面,我们在Android手机上看到的每一个界面就是一个activity. 二.Activity的创建 1.定义一个类继承activity,然后在清单文件manifest.xml文件的application节点下注册activity,这个activity就创建成功了. public class MyActivity extends Activity { } 2.清单文件注册activity <application android:a

Android四大组件之Activity详解

.Activity的本质 Activity是Android提供的四大组件之一,是进行Android开发必不可少的组件.Activity是一个界面的载体,可以把它与html页面进行类比,html页面由各种各样的标签组成,而Activity则可以由各种控件组成.然而Activity也并不是那么简单.查看Activity类的源码我们就可以看到,这个类大概有六千多行代码,说明Android对Activity的处理是相当复杂的.不过我们平时进行开发的时候不需要了解到那么深入的地步,因为我们可以根据Acti

第六课-Android四大组件之Activity

Activity是Android四大组件之一,它是个控制类,主要控制界面的加载显示,用户交互处理,数据的获取,数据的传送等.在它的onCreate方法中的setContentView方法就是来加载一个用户的界面. Activity既然是组件,把就必须要在清单文件中注册. Android每个界面的加载都需要Activity来完成. Android系统并不知道我们的应用要加载什么界面,它只知道应用会吧一个界面加载到一个手机窗口(Window)上,然后Window有setContentView方法来加

Android四大组件之——Activity(一)定义、状态和后退栈

什么是Activity 关键字:应用组件.四大组件.用户界面,交互. An Activity is an application component that provides a screen with which users can interact in order to do something 每个Android应用打开,一般都有界面与用户进行交互,以完成输入,输出等一些功能.提供这个功能的就是Android四大组件之一,Activity. Activity提供一个窗口描绘了用户界面,