java中的onresume_android onCreate onResume中获取 View 宽高为0分析

java中的onresume_android onCreate onResume中获取 View 宽高为0分析1、问题测试xmlns:tools=”http://schemas.android.com/tools”android:layout_width=”match_parent”android:layout_height=”match_parent”>android:id=”@+id/btn”android:layout_width=”100dp”android:layout_height=”4…

大家好,又见面了,我是你们的朋友全栈君。

1、问题测试

xmlns:tools=”http://schemas.android.com/tools”

android:layout_width=”match_parent”

android:layout_height=”match_parent”>

android:id=”@+id/btn”

android:layout_width=”100dp”

android:layout_height=”40dp” />

MainActivity.java

public class MainActivity extends AppCompatActivity {

private Button mBtn;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mBtn = (Button) findViewById(R.id.btn);

Log.d(“TAG”, “onCreate() button width=” + mBtn.getWidth());

}

@Override

protected void onResume() {

super.onResume();

mBtn.post(new Runnable() {

@Override

public void run() {

Log.d(“TAG”, “onResume() mBtn post button width=” + mBtn.getWidth());

}

});

new Handler().post(new Runnable() {

@Override

public void run() {

Log.d(“TAG”, “onResume() Handler button width=” + mBtn.getWidth());

}

});

}

}

log 结果:

85e4c433b732

image.png

根据上面的结果回产生4个疑问:

1、setContentView后获取控件的宽高为什么是0;

2、在 onResume中 handler.post 中获取控件的宽高为什么是0;

3、在 onResume中的 view.post 中为什么能获取控件宽高;

4、在 onResume 中handler.post 在 View.post 后面为什么执行反而在前面;

针对以上4个疑问进行解答

1、setContentView后获取控件的宽高为什么为0;

这个很好理解, setContentView只是解析了 xml 文件并创建了对应的控件,并没有进行控件的测量等工作;

2、在 onResume中 handler.post 中获取控件的宽高为什么是0;

ActivityThread.java类中handleResumeActivity函数

@Override

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,

String reason) {

…………

// TODO Push resumeArgs into the activity for consideration

final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);

if (r == null) {

// We didn’t actually resume the activity, so skipping any follow-up actions.

return;

}

…………

if (r.window == null && !a.mFinished && willBeVisible) {

r.window = r.activity.getWindow();

View decor = r.window.getDecorView();

decor.setVisibility(View.INVISIBLE);

ViewManager wm = a.getWindowManager();

WindowManager.LayoutParams l = r.window.getAttributes();

a.mDecor = decor;

l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

l.softInputMode |= forwardBit;

if (r.mPreserveWindow) {

a.mWindowAdded = true;

r.mPreserveWindow = false;

// Normally the ViewRoot sets up callbacks with the Activity

// in addView->ViewRootImpl#setView. If we are instead reusing

// the decor view we have to notify the view root that the

// callbacks may have changed.

ViewRootImpl impl = decor.getViewRootImpl();

if (impl != null) {

impl.notifyChildRebuilt();

}

}

if (a.mVisibleFromClient) {

if (!a.mWindowAdded) {

a.mWindowAdded = true;

wm.addView(decor, l);

} else {

// The activity will get a callback for this {@link LayoutParams} change

// earlier. However, at that time the decor will not be set (this is set

// in this method), so no action will be taken. This call ensures the

// callback occurs with the decor set.

a.onWindowAttributesChanged(l);

}

}

// If the window has already been added, but during resume

// we started another activity, then don’t yet make the

// window visible.

} else if (!willBeVisible) {

if (localLOGV) Slog.v(TAG, “Launch ” + r + ” mStartedActivity set”);

r.hideForNow = true;

}

…………..

}

Activity.onResume是在performResumeActivity中调用,此时还没有执行wm.addView(decor, l)创建 ViewRootImpl ,同时在 ViewRootImpl中的doTraversal()是通过mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null)发送异步消息等待下一个刷新消息才执行。所以 handler.post 消息回先执行导致获取 view 宽高失败。

ViewRootImpl.java中

@UnsupportedAppUsage

void scheduleTraversals() {

if (!mTraversalScheduled) {

mTraversalScheduled = true;

mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();

mChoreographer.postCallback(

Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

if (!mUnbufferedInputDispatch) {

scheduleConsumeBatchedInput();

}

notifyRendererOfFramePending();

pokeDrawLockIfNeeded();

}

}

3、在 onResume中的 view.post 中为什么能获取控件宽高;

View.java 中的 post()

public boolean post(Runnable action) {

//mAttachInfo 是在 ViewRootImpl 的构造函数中初始化的

//而 ViewRootmpl 的初始化是在 addView() 中调用

//所以此处的 mAttachInfo 为空,所以不会执行该 if 语句

final AttachInfo attachInfo = mAttachInfo;

if (attachInfo != null) {

return attachInfo.mHandler.post(action);

}

// Postpone the runnable until we know on which thread it needs to run.

// Assume that the runnable will be successfully placed after attach.

//保存消息到 RunQueue 中,等到在 performTraversals() 方法中被执行

getRunQueue().post(action);

return true;

}

通过第2点可以知道ViewRootImpl 的创建是在onResume 之后,所以此时attachInfo == null,从而消息被保存到RunQueue中,而RunQueue在ViewRootImpl的performTraversals被中执行,所以可以获取到控件宽高。

private void performTraversals(){

// Execute enqueued actions on every traversal in case a detached view enqueued an action

getRunQueue().executeActions(mAttachInfo.mHandler);

}

public void executeActions(Handler handler) {

synchronized (this) {

final HandlerAction[] actions = mActions;

for (int i = 0, count = mCount; i < count; i++) {

final HandlerAction handlerAction = actions[i];

handler.postDelayed(handlerAction.action, handlerAction.delay);

}

mActions = null;

mCount = 0;

}

}

4、在 onResume 中handler.post 在 View.post 后面为什么执行反而在前面;

通过上面第2点和点3点分析可以知道View.post的在后面performTraversals中被执行,而handler.post在performTraversals之前就被执行

85e4c433b732

image.png

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/137266.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • shiro面试必问_面试过程中的问题与对策

    shiro面试必问_面试过程中的问题与对策一,什么是Shiro?Shiro是apache旗下一个开源安全框架,它将软件的安全认证相关的功能抽取出来,实现用户身份授权,加密,会话管理等功能,组成了一个通用的安全认证框架二,目前市场主流的安全框架有哪些?(1),shiro:轻量级的,使用方便,灵活,是apache旗下一个开源安全框架,适合任何框架(2),SpringSeurity:是spring家族的一部分很多项目会使用到Spring全家桶,相对shiro来说SpringSeurity更轻量,必须要求spring环境,相对shiro

    2022年10月10日
  • 部署Vista – 第7部分:创建一个最小化的应答文件

    部署Vista – 第7部分:创建一个最小化的应答文件

  • 家庭影院.液晶电视.液晶电视连接电脑全功略续[通俗易懂]

    家庭影院.液晶电视.液晶电视连接电脑全功略续[通俗易懂]家庭影院.液晶电视.液晶电视连接电脑全功略续草木瓜20090201一、前言 《家庭影院.液晶电视.液晶电视连接电脑全功略》http://blog.csdn.net/liwei_cmg/archive/2008/11/28/3402883.aspx 一文中介绍了使用三星32A550P1R,作为电脑外接显示器+音箱的方法。其中中提到了 使用1366*768的分辨率。32A550物理

    2022年10月19日
  • Python获取Websocket接口的数据

    Python获取Websocket接口的数据作者:小小明在前面的用Tornado实现web聊天室一文中介绍了python实现websocket的方法,这篇文章将要分享如何用python作为客户端获取websocket接口的数据。前文链接:https://blog.csdn.net/as604049322/article/details/112386560websocket的使用WebSocket是一种在单个TCP/TSL连接上,进行全双工、双向通信的协议。WebSocket可以让客户端与服务器之间的数据交换变得更加简单高效,服务端.

  • 大数据资产管理实战

    大数据资产管理实战各位好,今天和大家分享“大数据资产管理实战”这个课题。本次分享包括大数据资产管理的概述、方法论和实施效果三个部分的内容。第一部分:大数据资产管理概述提到企业数字化转型,不得不提现在的一个主流观点:未来的企业必将成为数字化企业,每个公司都将会成为软件公司!未来企业增长和竞争的能力越来越取决于其数字化创新能力。为了应对企业数字化转型,企业IT架构采用分布式、微服务、移动化、大数据等技术来应对业务变化带…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号