浅析onWindowsFocusChanged()方法

前言

在接手的项目中,看到了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()方法后面。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值