之前对于Activity只关心它主要的生命周期函数,如onCreate()、onStart()、onResume()等,忽略了onWindowFocusChanged(boolean hasFocus)这个方法的存在。
但是在后来的学习中才逐渐了解到onResume()表示的是Activity处于运行期这样一种状态,它只是表示一种状态,而onWindowFocusChanged()则表示当前Activity获得或者失去焦点,当回调了这个方法时表示Activity是完全对用户可见的(只是可见,但是界面上还是一片黑呼呼的,有待draw..) 因此如果要统计Activity的渲染时间就可以使用这个方法作为渲染的结束时间。
在Activity生命周期中,onStart, onResume, onCreate都不是真正visible的时间点,真正的visible时间点是onWindowFocusChanged()函数被执行时。译注:从onWindowFocusChanged被执行起,用户可以与应用进行交互了,而这之前,对用户的操作需要做一点限制。
相信开发者都遇到过这样一种情况:经常会用到view的getWidth()、getHeight() 方法来获取该view的宽和高,如果是在onCreate()或者onResume()中调用返回的值经常都是0。
如果这个view的长宽很确定不为0的话,那么出现这种情况很可能是你过早的调用了这些方法,也就是说在这个view被加入到rootview之前你就调用了这些方法,返回的值自然为0。
解决这个问题的方法有很多,比如延缓调用这些获取宽高的方法,其中我觉得比较简单的一种方法就是在onWindowFocusChanged()中去获取控件View的width、height等信息(尤其适用于那种必须在Activity渲染完成后立马获取View宽高信息的情况)。
下面通过一个demo显示下Activity详细的生命周期:
布局文件activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.monkey.testwindowsfocus.MainActivity">
<com.example.monkey.testwindowsfocus.CustomImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@mipmap/ic_launcher"
android:scaleType="centerCrop"
android:id="@+id/btn_switch"/>
</RelativeLayout>
在布局文件中使用了一个自定义的CustomImageView,代码如下:
package com.example.monkey.testwindowsfocus;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
/**
* Created by monkey on 2016/12/26.
*/
public class CustomImageView extends ImageView{
public CustomImageView(Context context) {
super(context);
}
public CustomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.i(MainActivity.TAG, "onMeasure ");
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
Log.i(MainActivity.TAG, "onLayout ");
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.i(MainActivity.TAG, "onDraw ");
}
}
注:为了方便MainActivity和SecondActivity共用同一个布局文件,在MainActivty中点击CustomImageView跳转到SecondActivity。
MainActivity:
package com.example.monkey.testwindowsfocus;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
public static final String TAG = "TAG";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "MainActivity onCreate ");
initView();
}
private void initView() {
CustomImageView ivSwitch = (CustomImageView)findViewById(R.id.btn_switch);
ivSwitch.addOnLayoutChangeListener(
new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) {
Log.i(TAG, "MainActivity onLayoutChange ");
}
});
ivSwitch.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
}
}
);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
Log.i(TAG, "MainActivity onAttachedToWindow ");
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.i(TAG, "MainActivity onDetachedFromWindow ");
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Log.i(TAG, "MainActivity onWindowFocusChanged hasFocus--->"+hasFocus);
}
@Override
protected void onStart() {
super.onStart();
Log.i(TAG, "MainActivity onStart ");
}
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "MainActivity onResume ");
}
@Override
protected void onRestart() {
super.onRestart();
Log.i(TAG, "MainActivity onRestart ");
}
@Override
protected void onPause() {
super.onPause();
Log.i(TAG, "MainActivity onPause ");
}
@Override
protected void onStop() {
super.onStop();
Log.i(TAG, "MainActivity onStop ");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "MainActivity onDestroy ");
}
}
SecondeActivity:
package com.example.monkey.testwindowsfocus;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(MainActivity.TAG, "SecondActivity onCreate ");
initView();
}
private void initView() {
CustomImageView ivSwitch = (CustomImageView)findViewById(R.id.btn_switch);
ivSwitch.addOnLayoutChangeListener(
new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) {
Log.i(MainActivity.TAG, "SecondActivity onLayoutChange ");
}
});
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
Log.i(MainActivity.TAG, "SecondActivity onAttachedToWindow ");
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.i(MainActivity.TAG, "SecondActivity onDetachedFromWindow ");
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Log.i(MainActivity.TAG, "SecondActivity onWindowFocusChanged hasFocus--->"+hasFocus);
}
@Override
protected void onStart() {
super.onStart();
Log.i(MainActivity.TAG, "SecondActivity onStart ");
}
@Override
protected void onResume() {
super.onResume();
Log.i(MainActivity.TAG, "SecondActivity onResume ");
}
@Override
protected void onRestart() {
super.onRestart();
Log.i(MainActivity.TAG, "SecondActivity onRestart ");
}
@Override
protected void onPause() {
super.onPause();
Log.i(MainActivity.TAG, "SecondActivity onPause ");
}
@Override
protected void onStop() {
super.onStop();
Log.i(MainActivity.TAG, "SecondActivity onStop ");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(MainActivity.TAG, "SecondActivity onDestroy ");
}
}
点击App图标后的生命周期如下:
com.example.monkey.testwindowsfocus I/TAG: MainActivity onCreate
com.example.monkey.testwindowsfocus I/TAG: MainActivity onStart
com.example.monkey.testwindowsfocus I/TAG: MainActivity onResume
com.example.monkey.testwindowsfocus I/TAG:
MainActivity onAttachedToWindow
com.example.monkey.testwindowsfocus I/TAG: onMeasure
com.example.monkey.testwindowsfocus I/TAG: onMeasure
com.example.monkey.testwindowsfocus I/TAG: onMeasure
com.example.monkey.testwindowsfocus I/TAG: onMeasure
com.example.monkey.testwindowsfocus I/TAG: onLayout
com.example.monkey.testwindowsfocus I/TAG: MainActivity onLayoutChange
com.example.monkey.testwindowsfocus I/TAG:
MainActivity onWindowFocusChanged hasFocus—>true
com.example.monkey.testwindowsfocus I/TAG: onDraw
点击CustomImageView启动SecondActivity:
com.example.monkey.testwindowsfocus I/TAG: MainActivity onPause
com.example.monkey.testwindowsfocus I/TAG:
MainActivity onWindowFocusChanged hasFocus—>false
com.example.monkey.testwindowsfocus I/TAG: SecondActivity onCreate
com.example.monkey.testwindowsfocus I/TAG: SecondActivity onStart
com.example.monkey.testwindowsfocus I/TAG: SecondActivity onResume
com.example.monkey.testwindowsfocus I/TAG:
SecondActivity onAttachedToWindow
com.example.monkey.testwindowsfocus I/TAG: onMeasure
com.example.monkey.testwindowsfocus I/TAG: onMeasure
com.example.monkey.testwindowsfocus I/TAG: onMeasure
com.example.monkey.testwindowsfocus I/TAG: onMeasure
com.example.monkey.testwindowsfocus I/TAG: onLayout
com.example.monkey.testwindowsfocus I/TAG: SecondActivity onLayoutChange
com.example.monkey.testwindowsfocus I/TAG:
SecondActivity onWindowFocusChanged hasFocus—>true
com.example.monkey.testwindowsfocus I/TAG: onDraw
com.example.monkey.testwindowsfocus I/TAG: MainActivity onStop
在SecondActivity页面点击返回键:
com.example.monkey.testwindowsfocus I/TAG: SecondActivity onPause
com.example.monkey.testwindowsfocus I/TAG: MainActivity onRestart
com.example.monkey.testwindowsfocus I/TAG: MainActivity onStart
com.example.monkey.testwindowsfocus I/TAG: MainActivity onResume
com.example.monkey.testwindowsfocus I/TAG:
MainActivity onWindowFocusChanged hasFocus—>true
com.example.monkey.testwindowsfocus I/TAG: onDraw
com.example.monkey.testwindowsfocus I/TAG:
SecondActivity onWindowFocusChanged hasFocus—>false
com.example.monkey.testwindowsfocus I/TAG: SecondActivity onStop
com.example.monkey.testwindowsfocus I/TAG: SecondActivity onDestroy
com.example.monkey.testwindowsfocus I/TAG:
SecondActivity onDetachedFromWindow
在MainActivity页面点击返回键:
com.example.monkey.testwindowsfocus I/TAG:
MainActivity onWindowFocusChanged hasFocus—>false
com.example.monkey.testwindowsfocus I/TAG: MainActivity onPause
com.example.monkey.testwindowsfocus I/TAG: MainActivity onStop
com.example.monkey.testwindowsfocus I/TAG: MainActivity onDestroy
com.example.monkey.testwindowsfocus I/TAG:
MainActivity onDetachedFromWindow