Android: 在onCreate()中获得对象尺寸
onCreate() 中 View 尚未绘制完成
很多时候,我们需要在某个界面刚刚加载的时候,执行一些对 View 进行操作的代码,通常我们把这些代码放在 Activity 的 onCreate() 方法或 Fragment 的 onCreateView() 方法中。但因为在这些 Hook 方法被调用时,View 并没有绘制完成,很多操作不能生效。
比如,在 onCreate() 中调用某个按钮的 myButton.getHeight(),得到的结果永远是0。不想花时间慢慢看的同学,可以直接去看最后结论中的解决方案。
Button myButton = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
myButton = (Button) findViewById(R.id.button1);
// 尝试在 onCreate() 中获取控件尺寸
int h = myButton.getHeight();
Log.i(TAG, "onCreate(): Height=" + h); // 得到的结果是 Height=0
// ...
}
类似的情况还有很多,笔者之前自己写了一个下拉刷新的 ListView,希望在 Fragment 完成绘制后,立刻执行一次刷新,并将代码写在了 onCreateView() 中。结果是,列表确实进行了刷新操作,但是没有下拉刷新的动画。
更晚调用的生命周期函数
笔者开始以为,既然 onCreate() 中,控件尚未绘制完成,那么将代码写在更晚执行的一些生命周期函数中,问题是不是能得到解决呢?之后笔者分别在 Activity 中的一些常用的 Hook 函数中,尝试获取控件的尺寸,得到如下结果(按被执行的顺序排列):
onCreate(): Height=0
onStart(): Height=0
onPostCreate(): Height=0
onResume(): Height=0
onPostResume(): Height=0
onAttachedToWindow(): Height=0
onWindowsFocusChanged(): Height=1845
可以看到,直到 onWinodwsFocusChanged() 函数被调用,我们才能得到正确的控件尺寸。其他 Hook 函数,包括在官方文档中,描述为在 Activity 完全启动后才调用的 onPostCreate() 和 onPostResume() 函数,均不能得到正确的结果。
遗憾的是,虽然在 onWinodwsFocusChanged() 函数中,可以得到正确的控件尺寸。但这只在 Activity 中奏效,而在 Fragment 中,该方法并不能生效。
更多的解决方案
1. 使用 ViewTreeObserver 提供的 Hook 方法。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
myButton = (Button) findViewById(R.id.button1);
// 向 ViewTreeObserver 注册方法,以获取控件尺寸
ViewTreeObserver vto = myButton.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
int h = myButton.getHeight();
Log.i(TAG, "Height=" + h); // 得到正确结果
// 成功调用一次后,移除 Hook 方法,防止被反复调用
// removeGlobalOnLayoutListener() 方法在 API 16 后不再使用
// 使用新方法 removeOnGlobalLayoutListener() 代替
myButton.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
// ...
}
该方法在 onGlobalLayout() 方法将在控件完成绘制后调用,因而可以得到正确地结果。该方法在 Fragment 中,也可以使用。
2. 使用 View 的 post() 方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
myButton = (Button) findViewById(R.id.button1);
// 使用myButton 的 post() 方法
myButton.post(new Runnable() {
@Override
public void run() {
int h = myButton.getHeight();
Log.i(TAG, "Height=" + h); // 得到正确结果
}
});
// ...
}
该方法同样在 Fragment 中适用,是目前笔者发现的最佳解决方案。
注意:通过调用测量对象的 post() 方法注册的 Runnable 总在对象完全绘制后才调用,所以可以得到正确的结果。但直接在 onCreate() 中,使用 new Handler().post(mRunnable) 并不能得到正确的结果。
很多教程中,通过延迟一个毫秒数,即 new Handler().postDelayed(mRunnable, 500),来调用执行实际测量工作的 Runnable。这样虽然能得到正确的结果,但显然不是一个好的解决方案:太小的毫秒数不能保证控件完成绘制,太大的毫秒数,会严重破坏用户的操作体验。
结论
如果需要在某个 View 完成绘制后,立刻执行一段代码(如需要获取控件尺寸),最优雅的做法是:在 onCreate() 等生命周期函数中,调用该 View 的 post() 方法。
(参见上面的代码)
使用 ViewTreeObserver 注册 OnGlobalLayoutListener,或使用 Activity 的 onWinodwsFocusChanged() 方法,也可以达到相同目的。
Android: 在onCreate()中获得对象尺寸的更多相关文章
- Android在onCreate()中获得控件尺寸
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceSt ...
- Android在OnCreate中获取控件的宽度和高度
在Android中,有时需要对控件进行测量,得到的控件宽度和高度可以用来做一些计算.在需要自适应屏幕的情况下,这种计算就显得特别重要.另一方便,由于需求的原因,希望一进入界面后,就能得到控件的宽度和高 ...
- Android 在OnCreate()中获取控件高度与宽度
试过在OnCreate()中获取控件高度与宽度的童鞋都知道,getWidth()与getHeight()方法返回是0,具体原因 看一下Activity的生命周期 就会明白. 上代码: 方法一: int ...
- Android在onCreate中获取控件的宽高
在某些需求下,我们需要在onCreate的时候就获取到控件的宽高,但是如果直接用view.getWidth()或view.getHeight()会得到0.这是因为在onCreate执行的时候,控件还没 ...
- 如何获取Android系统中申请对象的信息
最近一直在做有关内存方面的优化工作,在做优化的过程,除了关注内存的申请量以及GC的情况之外,我们经常需要想方法找出是那些对象占用了大量内存,以及他们是如何导致GC的,这意味着我们需要获取对象申请的信息 ...
- Android中Parcelabel对象的使用和理解
1. Parcelable接口 Interface for classes whose instances can be written to and restored from a Parcel. ...
- Android应用项目中BaseAdapter、SimpleAdapter和ArrayAdapter中的三种适配器
一.写在前面: 本次我们来讲解一下Android应用中三个适配器:BaseAdapter.SimpleAdapter和ArrayAdapter.其中常见的是BaseAdapter,也是个人推荐使用的适 ...
- android Activity类中的finish()、onDestory()和System.exit(0) 三者的区别
android Activity类中的finish().onDestory()和System.exit(0) 三者的区别 Activity.finish() Call this when your a ...
- Android应用如何支持屏幕多尺寸多分辨率问题
作为Android应用程序开发者都知道android是一个“碎片化”的世界.多种系统版本.多种尺寸.多种分辨率.多种机型,还有不同的厂商定制的不同ROM,你开发的应用会在不可预期的手机上报错.这给开发 ...
随机推荐
- QoS专题-第5期-QoS实现之队列调度与报文丢弃
QoS实现之队列调度与报文丢弃 前面的专题里面介绍了通过优先级映射或者MQC对报文进行分类和标记,那么分类之后要做什么呢?那就是根据分类结果对报文进行流量控制处理.拥塞管理和拥塞避免就是两种流量控制手 ...
- 洛谷 P1023 税收与补贴问题 (2000NOIP提高组)
洛谷 P1023 税收与补贴问题 (2000NOIP提高组) 题意分析 一开始没理解题意.啰啰嗦嗦一大堆.看了别人的题解才明白啥意思. 对于样例来说,简而言之: 首先可以根据题目推算出来 28 130 ...
- 【bzoj3170】[Tjoi2013]松鼠聚会
3170: [Tjoi2013]松鼠聚会 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1670 Solved: 885[Submit][Statu ...
- [知识点]C++中STL容器之set
零.STL目录 1.容器之map 2.容器之vector 3.容器之set 一.前言 继上期的vector之后,我们又迎来了另一个类数组的STL容器——set. 二.用途与特性 set,顾名思义,集合 ...
- python基础----多态与多态性、super函数用法、继承原理
一.多态与多态性 ㈠多态: 多态指的是一类事物有多种形态, ...
- dorado事件
//----------------------------------------------------------------------------// //校验实体数据是否填写if(enti ...
- gitlab配置自动同步
如果需要同步到生产环境,请做额外处理,如自动化测试,测试通过再同步. <?php $project = trim($_GET['project']); if (empty($project)) ...
- Eclipse错误笔记!
1.ERROR: JDWP Unable to get JNI 1.2 environment, jvm->GetEnv() return code = -2 JDWP exit error ...
- 我的Git之旅(1)---git安装、github注册以及一些基本命令
蚂蚁作为一个混码农届的新人来说,看到什么东西都觉得高大上的感觉.最近接触到了git,有种蠢蠢欲动的感觉,想 试一把.因此开启了我的Git之旅.废话不多说,开始我的git之旅. 1.git服务器的选择 ...
- 接口自动化测试框架HttpRunner
接口自动化测试框架 https://github.com/HttpRunner/HttpRunner http://debugtalk.com/post/ApiTestEngine-api-test- ...