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)


相关推荐

  • Python中的/与//的区别

    Python中的/与//的区别在github的项目中的水仙花例题中:1fornuminrange(100,1000):2low=num//103mid=num//10%104high=num//10

  • 网络编程API-下 (I/O复用函数)[通俗易懂]

    网络编程API-下 (I/O复用函数)

  • CPU流水线技术演进「建议收藏」

    CPU流水线技术演进「建议收藏」一.三级线性流水线每个流水级的结构是:逻辑电路+寄存器我们可以将流水线往下细分,使得各个流水级足够小(CPU执行时间少),就可以通过提高系统时钟频率来提高CPU的处理速度。二.多级线性流水线(这里以5级为例)注意:我们把5级以上的流水线称为超流水线结构。三.muti-多级线性流水线(这里以5级为例)四.多级非线性流水线(乱序执行部件)五.超线程处理器多级非线性流水线(虚拟处理器共用乱序执行部件)拥有超线程的处理器将两个虚拟的处理器暴露给共享的乱..

  • 最全的vim快捷键

    最全的vim快捷键https://blog.csdn.net/flexman09/article/details/51802005 曾经使用了两年多的Vim,手册也翻过一遍。虽然现在不怎么用vim了,曾经的笔记还是贴出来,与喜欢vim的朋友分享。索1.关于Vimvim是我最喜欢的编辑器,也是linux下第二强大的编辑器。虽然emacs是公认的世界第一,我认为使用emacs并没有使用vi进行编…

  • Python 字典的定义以及常用方法

    Python 字典的定义以及常用方法定义(字典的key必须是不可变类型,也成为可hash类型,并且字典是无序的):info={'name':'egon','age':18,'se

  • python爬虫—–request模块学习及案例

    python爬虫—–request模块学习及案例

发表回复

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

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