WMS相关面试题

参考学习视频:阿里、腾讯等一线大厂必问的WMS面试题

问题一、View的绘制流程?onMeasure职责是做什么?

View绘制流程
在这里插入图片描述

问题二、Activity如何与window与view进行分工合作的?

在这里插入图片描述

在这里插入图片描述

ViewRootImpl是UI刷新的核心类,所有UI相关动作,包括触摸、触屏事件、响应事件、按键事件都是有ViewRootImpl来完成。
在这里插入图片描述

Activity的启动流程:在这里插入图片描述

ActivityThread.java

public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
        ... ...
        // 获取WindowManagerService的binder引用
        WindowManagerGlobal.initialize();
        ... ...
        final Activity a = performLaunchActivity(r, customIntent);
        ... ...
      
}

ActivityThread.java

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
 	... ...
 	// 通过类加载,找到activity
 	ava.lang.ClassLoader cl = appContext.getClassLoader();
    activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
    ... ...
    Window window = null;
    if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
         window = r.mPendingRemoveWindow;
         r.mPendingRemoveWindow = null;
         r.mPendingRemoveWindowManager = null;
     }
     appContext.setOuterContext(activity);
     activity.attach(appContext, this, getInstrumentation(), r.token,
             r.ident, app, r.intent, r.activityInfo, title, r.parent,
             r.embeddedID, r.lastNonConfigurationInstances, config,
             r.referrer, r.voiceInteractor, window, r.configCallback,
             r.assistToken);
       ... ...
         if (r.isPersistable()) {
             mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
         } else {
             mInstrumentation.callActivityOnCreate(activity, r.state);
         }
 }

Activity.java

final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
      	 ... ...

        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        ... ...
        // 设置WindowManager
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow()); 
        }
        //创建完成之后通过getWindowManager()就得到WindowManager 这个实例
        mWindowManager = mWindow.getWindowManager();   //这个就是WindowManagerImpl
}

  在此处构造了一个PhoneWindow,并进行了setWindowManager操作,此时Activity与Window就建立了联系。
  执行完了attach操作,就会返回上一个流程中执行mInstrumentation.callActivityOnCreate(activity, r.state),其实也就是调用了应用层的onCreate()方法。进而执行setContentView()方法解析xml文件(其实也就是序列化),创建一个根视图。

但是此时Window与View还没有建立联系

Activity生命周期是为了更好的管理Window,Window上面所显示的都是View。

接下来继续看Window如何与View进行建立联系的?
在这里插入图片描述
ActivityThread.java

@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
        String reason) {
		if (a.mVisibleFromClient) {  //a指Activity
            if (!a.mWindowAdded) {
                 a.mWindowAdded = true;
                 wm.addView(decor, l);  //wm指ViewManager, decor指View
             } 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);
             }
         }
}

ViewManager是一个接口,WindowManager类继承于ViewManager类,WindowManager是一个接口,具体实现类为WindowManagerImpl。

WindowManagerImpl.java

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        //mGlobal指WindowManagerGlobal,是一个单例
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    } 

private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
每个进程只有一个WindowManagerGlobal对象

WindowManagerGlobal.java

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {

	... ...
	 root = new ViewRootImpl(view.getContext(), display);  //此处创建一个根布局

     view.setLayoutParams(wparams);

     mViews.add(view);
     mRoots.add(root);
     mParams.add(wparams);
	 // do this last because it fires off messages to start doing things
     try {
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            if (index >= 0) {
                removeViewLocked(index, true);
            }
            throw e;
        }

}

ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {

	... ...
	res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
                            mTempInsets);
	... ...

}

即通过WindowSession进行IPC调用,将View添加到Window上
mWindow即W类(W继承于IWindow.Stub),用来接收WMS的消息,同时使用inputChannel接收触摸事件回调。

Session.java

/**
 * window   提供给  WMS  的回调接口
 * attrs layout 参数
 * outContentInsets  WMS计算后返回这个View在显示屏上的位置
 * outInputChannel   用户输入通道Handle
 *
 *
 /
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel)
	return mService.addWindow(this, window, seq, attrs, viewVisibility,displayId,outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);

Session类是继承于IWindowSession.Stub。
addWindowI()后面会调用WMS的WindowState操作,最后会交给SurfaceFling进行完成。

Activity中会有唯一的一个PhoneWindow,PhoneWindow包含了一个ViewRootImpl。

Activity生命周期是用来管理View,View的整个显示是由ViewRootImpl来完成的。

问题三、onResume函数中度量高有效吗?

答:Activity第一次调用onResume的时候是无效的,Activity第二次之后调用onResume是有效的。
  addView操作是在handleResumeActivity()方法中执行(ActivityThread.java),即PerformResumeActivity操作之后执行

  • 情况1,如果第一次进去的时候,执行到onResume函数获取度量高的值为0,此时WindowManager与DocorView还没进行相关的绑定。
  • 情况2,如果跳转到一个新的界面中,再返回该界面中,此时已经完成一次onResume的生命周期操作,UI已经度量完成,再返回onResume进行获取度量高是可以获取到值的。

handleResumeActivity–>performResumeActivity–>onResume–>WindowManager与 DecorView绑定

handleResumeActivity.java

@Override
 public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
	... ...
	 final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
	 ... ... 

}

handleResumeActivity.java

public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
            String reason) {
	... ...
	 r.activity.performResume(r.startsNotResumed, reason);
	... ...
}

Activity.java

final void performResume(boolean followedByPause, String reason) {


	... ...
	mInstrumentation.callActivityOnResume(this);
	... ...

}

最后调用应用层的OnResume()方法。在返回到ActivityThread的handleResumeActivity方法中。

ActivityThread.java

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
	... ... 
	final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); // 此步往下执行会执行到应用层的OnResume方法
	... ...
	if (r.activity.mVisibleFromClient) {
        r.activity.makeVisible();  //将ativity设置为可见,在里面添加add
     }
	
}

Activity.java

void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());  //将DecorView与WindowManager进行绑定
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }

问题四、线程中view.setText一定会报错吗,为什么?

答:不一定。

view.setText(“****”),最终触发调用的的invalidate(可以参考上图中的View绘制流程),触发不到刷新的流程,ViewRootImpl中的checkThread压根不会执行

问题五、View的绘制过程都是用的同一个canvas吗?

答:是的。canvas至始至终都是从ViewRootImpl通过参数传到View类中的draw(Canvas canvas)方法中,执行后续的draw流程。
canvas要lock锁住和unlock解锁操作。

问题六:Activity、Window、View三者的联系和区别?

答:Activity负责界面的交互和业务逻辑
window代表屏幕的一块显示区域,它是一个抽象的概念,是view的一个载体
view是显示的控件
window是view的一个容器view是window的一个真实实体内容
Activity向用户展示一个界面内容的时候,它本身并没有界面,需要通过window向用户展示。

问题七:首次View的绘制流程是在什么时候触发的?

答:WindowManagerImpl.addView() --> WindowManagerGlobal.addView() --> ViewRootImpl.setView() --> ViewRootImpl.requestLayout() -->ViewRootImpl.scheduleTraversals() -->后面就是执行绘制流程

问题八:调用invalidate()之后会马上进行屏幕刷新吗?

答:不会,必须等下一个同步信号VSYNC来了再进行刷新

问题九: 我们说丢帧是因为主线程做了耗时操作,为什么主线程做了耗时操作就会引起丢帧?

答:做了耗时操作就会影响下一帧的绘制,如果影响到了帧的绘制就会出现掉帧问题

问题十:连续两次setTextView到底会触发几次UI重绘呢?

答:UI必须至少等待16ms的间隔才会绘制下一帧,所有连续两次setTextView只会触发一次重绘。
在这里插入图片描述

问题十一:为什么Android APP的帧率一般是60FPS?

答:以电影为例,动画至少要得达到24FPS,才能保证画面的流畅度,低于这个值,肉眼会感觉到卡顿。在手机上,这个值被调整到60FPS,增加丝滑度,这也是为什么有个(1000/60)16ms的指标,一般而言目前的Android系统FPS也就是60,它是通过一个VSYNC来保证每16ms最多绘制一帧。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: WMS仓库管理系统是对仓储货物的收发、结存等活动进行有效控制的系统。它的目的是保证仓储货物的完好无损,确保生产经营活动的正常进行,并对各类货物的活动状况进行分类记录,以便进行综合管理。\[2\]在开发WMS仓库管理系统时,通常会通过项目经理与仓库管理人员的沟通,了解具体的业务需求,并将这些需求以文档的形式下发给开发团队。开发团队根据文档中的要求进行系统开发,包括仓库区的管理、库存数量的控制、货品进出仓库的控制等。\[1\]\[3\]同时,仓库管理系统还需要考虑容器的使用与保管维修等方面的管理。 #### 引用[.reference_title] - *1* [仓储管理系统(面试问答)](https://blog.csdn.net/qq_36165926/article/details/75255391)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [wms仓库管理流程的基本作业](https://blog.csdn.net/shly2009/article/details/118363547)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值