浅析onWindowsFocusChanged()方法

来源:互联网 发布:n卡优化 编辑:程序博客网 时间:2024/06/16 01:25

前言

在接手的项目中,看到了onWindowsFocusChanged()的方法,抽空了解下它的用途

内容

概述

   从字面上来讲,onWindowsFocusChanged()方法是指当窗口焦点变化的时候;从意义来说,onWindowsFocusChanged()就是指当前的Activity的Windows(窗口)获取或者失去焦点时这个方法就会被调用,并且当回调这个方法时,Activity是完全可见的。

   在Activity生命周期中,onStart(), onResume(), onCreate()都不是布局visible的时间点,真正的visible时间点是onWindowFocusChanged()函数被执行时。从onWindowFocusChanged()被执行起,用户可以与应用进行交互了,换句话说,如果你想要在Activity加载后做些操作,可以在这个方法里调用而这之前,对用户的操作需要做一点限制。

onWindowFocusChanged()的使用情景与作用

   根据介绍可以了解,onWindowFocusChanged()使用于以下等情景:

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

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

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

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

  5. 应用进入后台,窗口失去焦点;

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

   因此其可以有如下作用:

  1. 监控一个Activity是否载完毕;

  2. 在Activity加载后进行一些操作,如获取手机屏幕的高度和宽度;

  3. 当Activity挂起或恢复时,可以在方法内进行一些数据的保存或恢复的操作;

onWindowFocusChanged()调用详解

   介绍完onWindowFocusChanged()基本的使用情景以及作用后,撸个demo来看下onWindowFocusChanged()具体的调用情况。

   首先在Activity中重写的onWindowFocusChanged()方法如下:

/**     * 添加窗体在视图初始化完成过后     *     * @param hasFocus     */    @Override    public void onWindowFocusChanged(boolean hasFocus) {        super.onWindowFocusChanged(hasFocus);        if (hasFocus) {           //add Window.....        }    }  

   其中参数hasFocus表示窗口是否获取或失去焦点,true表示获取焦点,false表示失去焦点。

   然后我们看下总体的代码:

public class WindosFoucesDemo extends AppCompatActivity {    private static final String TAG = "LifeCycleDemo";    //Activity创建时被调用    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.i(TAG, "onCreate is called.");        setContentView(R.layout.activity_main);    }    //Activity创建或者从后台重新回到前台时被调用    @Override    protected void onStart() {        super.onStart();        Log.i(TAG, "onStart is called.");    }    //Activity创建或者从被覆盖、后台重新回到前台时被调用    @Override    protected void onResume() {        super.onResume();        Log.i(TAG, "onResume is called.");    }    //Activity窗口获得或失去焦点时被调用,在onResume之后或onPause之后    @Override    public void onWindowFocusChanged(boolean hasFocus) {        super.onWindowFocusChanged(hasFocus);        if(hasFocus){            Log.i(TAG, "onWindowFocusChanged is called and" + "hasFocus is true");        }else {            Log.i(TAG, "onWindowFocusChanged is called and" + "hasFocus is false");        }    }    //Activity被覆盖到下面或者锁屏时被调用    @Override    protected void onPause() {        super.onPause();        Log.i(TAG, "onPause is called.");        //有可能在执行完onPause或onStop后,系统资源紧张将Activity杀死,所以有必要在此保存持久数据    }    //退出当前Activity或者跳转到新Activity时被调用    @Override    protected void onStop() {        super.onStop();        Log.i(TAG, "onStop is called.");    }    //退出当前Activity时被调用,调用之后Activity就结束了    @Override    protected void onDestroy() {        super.onDestroy();        Log.i(TAG, "onDestory is called.");    }    //Activity从后台重新回到前台时被调用    @Override    protected void onRestart() {        super.onRestart();        Log.i(TAG, "onRestart called.");    }}

   运行该Demo,查看Log日志,可以得到以下日志结果。

   1. 启动Activity时:

image

   2. 按下任务栏键,Activity被遮挡时:

image

注意:按锁屏键和按任务栏或者Home键的生命周期是不同的,按Home执行onPause –> onStop –> onRestart –> onStart —> onResume 按锁屏键和对话框覆盖界面的生命周期是一样的,都只会进行onPause --> onResume .不会执行onStop,onRestart,onStart。

   3. Activity恢复到前台时:

image

   4. Activity退出时:

image

   从上面的例子以及结果可以清楚的onWindowFocusChanged()在整个Activity生命周期内的调用情况,可以根据这些结果,在开发中来充分利用onWindowFocusChanged()方法的作用。

onWindowFocusChanged()源码分析

   通过Activity源码去查看,发现onWindowFocusChanged()这个方法出现在WindowCallbackWrapper.java和View.java这两个类中,而WindowCallbackWrapper.java中其实也是调用View.java中的onWindowFocusChanged(),其代码如下:

     /**     * 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.     * 当前的window(窗口)获取或者失去焦点的时候会回调这个方法.请注意,这个焦点和     * view焦点是分离的,为了获取按键事件,view和view所在的窗口都必须获得焦点.如果 * 一个窗口处于你的输入事件的最上层,那么该窗口将失去焦点而view的焦点会保持不     * 变.     */    public void onWindowFocusChanged(boolean hasWindowFocus) {        //获取软键盘a system window such as the keyguard may         InputMethodManager imm = InputMethodManager.peekInstance();        if (!hasWindowFocus) {            if (isPressed()) {                  //键盘有按下事件,则强制将该view包含的所有子控件全部setPressed()设置为false                setPressed(false);            }            if (imm != null && (mPrivateFlags & FOCUSED) != 0) {                //这是一个隐藏的方法(带@hide标签),当view失去焦点时会调用该方法                imm.focusOut(this);            }            //移onWindowFocusChanged(boolean hasFocus) 被回调的触发时机是窗口获取或失去焦点的时候.除长按事件回调的接口方法            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();    }

   从源码可以验证出,onWindowFocusChanged()方法被回调的触发时机是窗口获取或失去焦点的时候。并且在onResume()方法中的官方解释 Use {@link #onWindowFocusChanged} to know for certain that your activity is visible to the user (for example, to resume a game). 可以知道onWindowFocusChanged()第一次调用是在onResume()方法后面。

原创粉丝点击