Android查缺补漏(View篇)--在 Activity 的 onCreate() 方法中为什么获取 View 的宽和高为0?

在 Activity 的 onCreate() 方法中为什么获取 View 的宽和高为0 ?

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my_view);
    myview = ViewUtils.find(this, R.id.myview);
    getViewSize("onCreate");
}
private void getViewSize(String methodTag) {
    int width = myview.getWidth();
    int height = myview.getHeight();

    Log.i(TAG, methodTag + ": width=" + width + " | height=" + height);
}

log如下:

12-15 17:04:55.470 29286-29286/cn.codingblock.view I/MyViewActivity: onCreate: width=0 | height=0

如上面代码结果所示,在Activity的onCreate()方法中我们尝试获取控件的宽和高,却获取得是0,这是因为 View 绘制和 Activity 的生命周期方法并不同步,即使 Activity 回调了 onCreate()、onStart()、onResume() 方法,View 也不一定同步完成绘制,所以此时在这些方法里面获取 View 的尺寸时就获取不到,解决方法有以下几种:

方法一、在 Activity 的 onWindowFocusChanged() 方法中获取 View 的尺寸。

在 Activity 中,当对所有的 View 初始化完毕后,会回调 onWindowFocusChanged() 方法。
/**
 * 方案一
 * 当 View 初始化完毕是回调
 * 当 Activity 每次获取和失去焦点时回调
 * @param hasFocus
 */
@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    getViewSize("onWindowFocusChanged");
}

方法二、使用 View.post() 将任务post到消息队列中,当view初始化完毕后looper会执行任务。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my_view);
    myview = ViewUtils.find(this, R.id.myview);
    // 方案二、将任务post到消息队列中,当view初始化完毕后looper会执行任务
    myview.post(new Runnable() {
        @Override
        public void run() {
            getViewSize("post");
        }
    });
}

方法三、可以使用 ViewTreeObserver 的一些监听接口。

例如:当 View 树的状态或者 View 树内部的 View 的可见性发生改变时,ViewTreeObserver.OnGlobalLayoutListener 接口的 onGlobalLayout() 会被回调,可以在此方法内部获取 View  的尺寸。
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my_view);
    myview = ViewUtils.find(this, R.id.myview);
    // 方案三、当 View 树的状态或者 View 树内部的 View 的可见性发生改变时,
    // ViewTreeObserver.OnGlobalLayoutListener 接口的 onGlobalLayout() 会被回调,
    // 可以在此方法内部获取 View  的尺寸
    ViewTreeObserver observer = myview.getViewTreeObserver();
    observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            getViewSize("onGlobalLayout");
        }
    });
}

当然除了以上方法之外还会有其他的方法,例如可以使用延时或者在onCreate()方法中手动调用 View 的测量方法,相对而言以上几种方法更为方便。



最后想说的是,本系列文章为博主对Android知识进行再次梳理,查缺补漏的学习过程,一方面是对自己遗忘的东西加以复习重新掌握,另一方面相信在重新学习的过程中定会有巨大的新收获,如果你也有跟我同样的想法,不妨关注我一起学习,互相探讨,共同进步!

参考文献:

  • 《Android开发艺术探索》
  • 《Android开发进阶从小工到专家》

原文地址:https://www.cnblogs.com/codingblock/p/8067205.html

时间: 2024-08-01 22:46:10

Android查缺补漏(View篇)--在 Activity 的 onCreate() 方法中为什么获取 View 的宽和高为0?的相关文章

Android查缺补漏(View篇)--自定义 View 的基本流程

View是Android很重要的一部分,常用的View有Button.TextView.EditView.ListView.GridView.各种layout等等,开发者通过对这些View的各种组合以形成丰富多彩的交互界面,一个应用中界面交互的体验往往在应用的受欢迎程度上起了很关键得作用,所以开发者们大多会想方设法的做出一个更加精美的界面,例如:通过自定义View.深入学习View的原理以便更好的对其优化使其在操作起来更加流畅等等,也正因为如此,在面试中View也常常作为面试官重点考察的对象之一

Android查缺补漏(View篇)--事件分发机制源码分析

在上一篇博文中分析了事件分发的流程及规则,本篇会从源码的角度更进一步理解事件分发机制的原理,如果对事件分发规则还不太清楚的童鞋,建议先看一下上一篇博文 <Android查缺补漏(View篇)--事件分发机制> ,先来看一下本篇的分析思路,一会儿会按照事件传递的顺序,针对以下几点进行源码分析: Activity对点击事件的分发过程 PhoneWindow是如何处理点击事件的 顶级View对点击事件的分发过程 View对点击事件的处理过程 Activity对点击事件的分发过程 通过上一篇博文中我们

Android查缺补漏(线程篇)-- IntentService的源码浅析

本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8975114.html 在Android中有两个比较容易弄混的概念,Service和Thread,我们都知道这两个东西都可以执行后台任务,但要注意的是Service是跑在主线程中的,如果不做特殊处理是会阻塞主线程的,而IntentService正好弥补了这一点,在<Android查缺补漏--Service和IntentService>这篇博文中已经简单介绍过了IntentSe

在Activity的onCreate方法中显示PopupWindow导致异常的原因分析及解决方案

一.前言 在某些情况下,我们需要一进入Activity就显示PopupWindow,比如常见的选择界面.但由于PopupWindow是依附于Activity的,如果Activity没有创建完成,Activity还没完全显示出来就显示PopupWindow的话,会出现异常现象. 二.问题复现 我在Activity的onCreate()方法中调用如下方法: public void show( ){ if( null != mPopupWindow ){ mPopupWindow.showAtLoca

在Activity的oncreate方法中如果跳转到别的activity,会发生什么

真是日*狗,即便你跳转到别的Activity,其余的代码一样执行 首先做实验,证明它就是这样发生的 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); System.out.println("aaaaaaaaaaaaaaaaaa"); new Thread(new R

Android查缺补漏(View篇)--自定义View利器Canvas和Paint详解

上篇文章介绍了自定义View的创建流程,从宏观上给出了一个自定义View的创建步骤,本篇是上一篇文章的延续,介绍了自定义View中两个必不可少的工具Canvas和Paint,从细节上更进一步的讲解自定义View的详细绘制方法.如果把自定义View比作盖一座房子,那么上篇文章就相当于教会了我们怎么一步步的搭建房子的骨架,而本篇文章将要教会我们的是为房子的骨架添砖加瓦直至成型,甚至是怎么装修. Canvas 为了后文更为方便的讲解Canvas的常用方法的使用,我们先来做一些准备工作,创建一个自定义V

Android查缺补漏--Service和IntentService

Service的运行不依赖界面,即使程序被切换到后台,Service仍然能够保持正常运行.当某个应用程序进程被杀掉时,所有依赖于该进程的Service也会停止运行. Service 分为启动状态和绑定状态.当处于仅启动状态时,通过 stopService或 stopSelf 即可停止 Service.当处于绑定状态时需要通过 unBindService 和 stopService 结合使用才能完全停止 Service. 一.Service的生命周期(onCreate()-onStartComma

Android查缺补漏--ContentProvider的使用

ContentProvider (内容提供者)是一种共享型组件,可以为系统内应用于与应用之间提供访问接口. ContentProvide要想正常工作需要三个关键点: ContentProvider:对外提供数据的访问接口. Uri:ContentProvider的唯一标识,外界可根据其访问对应的ContentProvider. ContentResolver 比如,当应用A想把自己数据暴露出来让别的应用也可以操作的话,就可以在应用A内部创建一个ContentProvider实现相关方法并添加UR

Android查缺补漏(View篇)--自定义 View 中 wrap_content 无效的解决方案

自定义 View 中 wrap_content 无效的解决方案 做过自定义 View 的童鞋都会发现,直接继承 View 的自定义控件需要重写 onMeasure() 方法,并设置 wrap_content 时的自身大小,否在在布局文件中对自定义控件在设置大小时,wrap_content 将等同于 match_parent. 其实在 Android 中自带的控件中,也都对 onMeasure() 方法进行了重写,对于 wrap_content 等情况做了特殊处理,在 wrap_content 时