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

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 钢琴初学者怎样自学五线谱_小星星五线谱钢琴

    钢琴初学者怎样自学五线谱_小星星五线谱钢琴适用于程序员的钢琴教程这是由山东琴律信息科技有限公司制作的‘钢琴五线谱入门教程’全集分为五集。分别为:这是由山东琴律信息科技有限公司制作的‘钢琴五线谱入门教程’全集分为五集。分别为:钢琴(带你认识钢琴,琴键,调式等)音高(把五线谱中的音高部分单独拿出来讲)音值(把音值部分也单独拿出来讲)音强(五线谱的音强部分)总结(把一首曲子分为音高音值和音强三个方面进行分解,并总结)有想学习钢琴,乐理,识谱方面知识的大家可以关注一下,对于我们理科出身的用户还是比较友好的。B站也有很多用户非常喜欢。所

    2022年8月29日
    1
  • 计算机专业的男生喜欢你,【男生这十个反应说明他喜欢你】_男人的10个表现说明他喜欢上了你…

    计算机专业的男生喜欢你,【男生这十个反应说明他喜欢你】_男人的10个表现说明他喜欢上了你…[onlylady乐活健康情感]男人是一种奇怪动物.和他看不上的女人说话时,他表现得十分自然大方,仿佛兄弟.和他看上的女人说话时,则表现得有点扭捏.1、和女人说话时,不太敢正面女人,而是常常温柔地瞟女人.男人是一种奇怪动物.和他看不上的女人说话时,他表现得十分自然大方,仿佛兄弟.和他看上的女人说话时,则表现得有点扭捏.并非缺乏正面女人的勇气,而是心底不由自主的害羞在作祟.对了,还有一种伴发症…

    2022年7月25日
    4
  • 深入了解ZooKeeper(一)

    1.内容思维导图2.分布式协调技术在进程间通讯中为了防止资源的竞争和抢占,我们有很多方法(如原子函数,互斥锁,事件,信号等)去实现临界资源的有序访问。那么处于分布式的环境中时,我们又该如何去处

    2021年12月28日
    58
  • VLAN的基本配置_划分不全的例子

    VLAN的基本配置_划分不全的例子1、VLAN基础知识VLAN(VirtualLocalAreaNetwork)的中文名为:“虚拟局域网”,注意和’VPN’(虚拟专用网)进行区分。VLAN是一种将局域网设备从逻辑上划分(不是从物理上划分)成一个个网段,从而实现虚拟工作组的新兴数据交换技术。这一新兴技术主要应用于交换机和路由器中,但主流应用还是在交换机之中。但又不是所有交换机都具有此功能,只有VLAN协议的第三层以上交换机才具有此功能,这一点可以查看相应交换机的说明书即可得知。由于它是从逻辑上划分,而不是从物理上..

    2022年9月19日
    0
  • web渗透测试—-33、HttpOnly[通俗易懂]

    web渗透测试—-33、HttpOnly[通俗易懂]HttpOnly是微软公司的InternetExplorer6SP1引入的一项新特性。这个特性为cookie提供了一个新属性,用以阻止客户端脚本访问Cookie,至今已经称为一个标准,几乎所有的浏览器都会支持HttpOnly。下面示例显示了HTTP响应标头中HttpOnly使用的语法:Set-Cookie:<name>=<value>[;<Max-Age>=<age>]`[;expires=<date>][;domain=&lt

    2022年6月30日
    38
  • shell脚本之环境变量

    shell脚本之环境变量linux系统环境变量配置文件所在位置/etc/profile/etc/profiled/*.sh~/.bash_profile~/.bashrc/etc/bashrc配置文件的执行过程注销时生效的环境变量配置文件~/.bash_logout历史命令存储位置~/bash_historyshell登录信息本地终端欢迎信息:/etc/issue远程终端欢迎信息:/etc…

    2022年5月27日
    42

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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