Android 13 平板Taskbar加载流程

简介: Android 13 平板Taskbar加载流程

学习笔记:

从 Android 12开始,如果是大屏底下导航栏会变成显示一个任务栏,从 NavigationBar 变成 Taskbar 。

注:CentralSurfacesImpl.java 与 原来的 statusbar.java 的作用一样。

CentralSurfacesImpl 的启动流程前面有说过,这里不在说明。

// CentralSurfacesImpl.java
public class CentralSurfacesImpl extends CoreStartable implements
        CentralSurfaces {
     //省略其他代码....
    protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
        //省略其他代码....
        createNavigationBar(result);
       //省略其他代码....
    }
    protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
        // 调用 NavigationBarController 的 createNavigationBars()方法创建 NavigationBar
        mNavigationBarController.createNavigationBars(true /* includeDefaultDisplay */, result);
    }
}

接着往下看:

NavigationBarController#createNavigationBars()

// NavigationBarController.java
    public void createNavigationBars(final boolean includeDefaultDisplay,
            RegisterStatusBarResult result) {
        // 如果需要,更新辅助功能按钮模式
        updateAccessibilityButtonModeIfNeeded();
        // 这里是重点,Android 12 之前版本的,没有这个判断。可以看下 initializeTaskbarIfNecessary() 方法。
        // 如果我们初始化TaskBar,则不需要在默认显示上创建导航栏
        final boolean shouldCreateDefaultNavbar = includeDefaultDisplay
                && !initializeTaskbarIfNecessary();
        Display[] displays = mDisplayManager.getDisplays();
        for (Display display : displays) {
            if (shouldCreateDefaultNavbar || display.getDisplayId() != DEFAULT_DISPLAY) {
                createNavigationBar(display, null /* savedState */, result);
            }
        }
    }
    /** @return {@code true} if taskbar is enabled, false otherwise */
    private boolean initializeTaskbarIfNecessary() {
        // 这里会判断是否是平板。
        // 跟踪代码发现,如果屏幕的(最小边长度*160/dpi值)< 600,就会判断为设备是平板设备
        // system/vendor/mediatek/proprietary/packages/apps/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
        if (mIsTablet) {
            Trace.beginSection("NavigationBarController#initializeTaskbarIfNecessary");
            // 移除导航栏
            removeNavigationBar(mContext.getDisplayId());
            // 加载任务栏
            mTaskbarDelegate.init(mContext.getDisplayId());
            Trace.endSection();
        } else {
            mTaskbarDelegate.destroy();
        }
        return mIsTablet;
    }

我们分析平板,所以这里直接看  mTaskbarDelegate.init(mContext.getDisplayId()) 方法;

TaskbarDelegate#init()

// TaskbarDelegate.java
    public void init(int displayId) {
        if (mInitialized) {
            return;
        }
        //省略其他代码....
        // 注册监听,切换导航模式时接收回调。
        mEdgeBackGestureHandler.onNavigationModeChanged(
                mNavigationModeController.addListener(this));
        // 边缘手势处理,注意:这里只加载、处理手势。
        // 手势中左右两返回图标由这里加载,底部黑色小横条不在这里加载。
        mEdgeBackGestureHandler.onNavBarAttached();
        //省略其他代码....
    }
    // 导航模式改变回调,进行处理
    @Override
    public void onNavigationModeChanged(int mode) {
        mNavigationMode = mode;
        mEdgeBackGestureHandler.onNavigationModeChanged(mode);
    }

1、手势加载

EdgeBackGestureHandler#onNavBarAttached()

// EdgeBackGestureHandler.java
    /**
     * @see NavigationBarView#onAttachedToWindow()
     */
    public void onNavBarAttached() {
        mIsAttached = true;
        mProtoTracer.add(this);
        mOverviewProxyService.addCallback(mQuickSwitchListener);
        mSysUiState.addCallback(mSysUiStateCallback);
        // 重点关注这里,更新视图
        updateIsEnabled();
        startTracking();
    }
    private void updateIsEnabled() {
        // mIsAttached 是否已经添加上了,mIsGesturalModeEnabled 是否启用手势模式
        boolean isEnabled = mIsAttached && mIsGesturalModeEnabled;
        if (isEnabled == mIsEnabled) {
            return;
        }
        mIsEnabled = isEnabled;
        // 如果无效的话结束监听 Input
        disposeInputChannel();
        if (mEdgeBackPlugin != null) {
            // 边缘导航栏销毁
            mEdgeBackPlugin.onDestroy();
            mEdgeBackPlugin = null;
        }
        // 是否启用手势模式
        if (!mIsEnabled) {
             // 注销监听返回手势参数的设置变化
            mGestureNavigationSettingsObserver.unregister();
            if (DEBUG_MISSING_GESTURE) {
                Log.d(DEBUG_MISSING_GESTURE_TAG, "Unregister display listener");
            }
            mPluginManager.removePluginListener(this);
            TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
            DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
            try {
                 // 注销 WMS 里保存的除外区域监听
                mWindowManagerService.unregisterSystemGestureExclusionListener(
                        mGestureExclusionListener, mDisplayId);
            } catch (RemoteException | IllegalArgumentException e) {
                Log.e(TAG, "Failed to unregister window manager callbacks", e);
            }
        } else {
            // 监听返回手势参数的设置变化
            mGestureNavigationSettingsObserver.register();
            updateDisplaySize();
            if (DEBUG_MISSING_GESTURE) {
                Log.d(DEBUG_MISSING_GESTURE_TAG, "Register display listener");
            }
            TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
            DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
                    mMainExecutor::execute, mOnPropertiesChangedListener);
            try {
                // 监听 WMS 里保存的除外区域
                mWindowManagerService.registerSystemGestureExclusionListener(
                        mGestureExclusionListener, mDisplayId);
            } catch (RemoteException | IllegalArgumentException e) {
                Log.e(TAG, "Failed to register window manager callbacks", e);
            }
            //  注册名为 edge-swipe 的InputMonitor
            mInputMonitor = InputManager.getInstance().monitorGestureInput(
                    "edge-swipe", mDisplayId);
            mInputEventReceiver = new InputChannelCompat.InputEventReceiver(
                    mInputMonitor.getInputChannel(), Looper.getMainLooper(),
                    Choreographer.getInstance(), this::onInputEvent);
            // 添加 NavigationBarEdgePanel 为 Edge Back 事件的处理实现
            setEdgeBackPlugin(
                    new NavigationBarEdgePanel(mContext, mBackAnimation, mLatencyTracker));
            mPluginManager.addPluginListener(
                    this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
        }
        // 更新 ML 模型资源.
        updateMLModelState();
    }
    // 创建返回手势视图
    private void setEdgeBackPlugin(NavigationEdgeBackPlugin edgeBackPlugin) {
        if (mEdgeBackPlugin != null) {
            mEdgeBackPlugin.onDestroy();
        }
        // 缓存 NavigationEdgeBackPlugin 实现
        mEdgeBackPlugin = edgeBackPlugin;
        // 向 NavigationEdgeBackPlugin 注册 Back 手势的触发回调
        mEdgeBackPlugin.setBackCallback(mBackCallback);
        // 准备好手势视图的 Window 参数
        mEdgeBackPlugin.setLayoutParams(createLayoutParams());
        updateDisplaySize();
    }
    // 配置返回手势 Window 的参数
    // 包括 flag、type、title 等属性
    private WindowManager.LayoutParams createLayoutParams() {
        Resources resources = mContext.getResources();
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                resources.getDimensionPixelSize(R.dimen.navigation_edge_panel_width),
                resources.getDimensionPixelSize(R.dimen.navigation_edge_panel_height),
                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
                PixelFormat.TRANSLUCENT);
        ...
        layoutParams.setTitle(TAG + mContext.getDisplayId());
        layoutParams.setFitInsetsTypes(0 /* types */);
        layoutParams.setTrustedOverlay();
        return layoutParams;
    }

到此手势导航创建完成,注意:此时 View 还是不可见的,后续事件产生的时候会进行展示和刷新。

下面粗略的看下手势相关的事件:

// EdgeBackGestureHandler.java
    private void onMotionEvent(MotionEvent ev) {
        int action = ev.getActionMasked();
        if (action == MotionEvent.ACTION_DOWN) {
            mInputEventReceiver.setBatchingEnabled(false);
            mIsOnLeftEdge = ev.getX() <= mEdgeWidthLeft + mLeftInset;
            mMLResults = 0;
            mLogGesture = false;
            mInRejectedExclusion = false;
            boolean isWithinInsets = isWithinInsets((int) ev.getX(), (int) ev.getY());
            // 根据返回手势是否有效、
            // 点击区域是否是停用区域等条件
            // 得到当前是否允许视图处理该手势
            mAllowGesture = !mDisabledForQuickstep && mIsBackGestureAllowed && isWithinInsets
                    && !mGestureBlockingActivityRunning
                    && !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
                    && isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
            if (mAllowGesture) {
                // 更新当前是屏幕左侧还是右侧
                mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge);
                // 发射事件给视图
                mEdgeBackPlugin.onMotionEvent(ev);
            }
        } else if (mAllowGesture || mLogGesture) {
            if (!mThresholdCrossed) {
                mEndPoint.x = (int) ev.getX();
                mEndPoint.y = (int) ev.getY();
                // 多个手指按下的话取消事件处理
                if (action == MotionEvent.ACTION_POINTER_DOWN) {
                    if (mAllowGesture) {
                        logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_MULTI_TOUCH);
                        cancelGesture(ev);
                    }
                    mLogGesture = false;
                    return;
                } else if (action == MotionEvent.ACTION_MOVE) {
                    // 手指移动超过长按阈值的话
                    // 也要取消事件处理
                    if ((ev.getEventTime() - ev.getDownTime()) > mLongPressTimeout) {
                        if (mAllowGesture) {
                            logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_LONG_PRESS);
                            cancelGesture(ev);
                        }
                        mLogGesture = false;
                        return;
                    }
                    ...
                }
            }
            // 通过上述检查的话
            // 将 MOVE、UP 交给视图
            if (mAllowGesture) {
                // forward touch
                mEdgeBackPlugin.onMotionEvent(ev);
            }
        }
        mProtoTracer.scheduleFrameUpdate();
    }

事件间传递到 NavigationBarEdgePanel ,进行展示返回手势和触发返回。

NavigationBarEdgePanel 继续进行后面的工作:手势的判断、视图的刷新、动画的展示。

onMotionEvent() 的逻辑:

  • DOWN 的时候先让视图变为可见 VISIBLE
  • MOVE 的处理通过 handleMoveEvent() 判断距离,决定是否要更新赋予 mTriggerBack
  • UP 的时候将检查该变量决定是否触发返回动作即 triggerBack()

// NavigationBarEdgePanel.java
    public void onMotionEvent(MotionEvent event) {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                mDragSlopPassed = false;
                resetOnDown();
                mStartX = event.getX();
                mStartY = event.getY();
                setVisibility(VISIBLE);
                updatePosition(event.getY());
                mRegionSamplingHelper.start(mSamplingRect);
                mWindowManager.updateViewLayout(this, mLayoutParams);
                break;
            case MotionEvent.ACTION_MOVE:
                handleMoveEvent(event);
                break;
            case MotionEvent.ACTION_UP:
                if (mTriggerBack) {
                    triggerBack();
                } else {
                    cancelBack();
                }
                ...
        }
    }

手势相关的事件流程到此打住了。

2、按钮导航

按钮导航是在 TouchInteractionService.java 中的 onCreate() 方法开始的。

// TouchInteractionService.java
    @Override
    public void onCreate() {
        super.onCreate();
        //省略其他代码....
        mTaskbarManager = new TaskbarManager(this);
        //省略其他代码....
    }

用户配置完成后,根据配置,是否加载按钮导航。如果加载则会调用 TaskbarManager.java中的 recreateTaskbar() 方法。

TaskbarManager#recreateTaskbar()

// TaskbarManager.java
    private void recreateTaskbar() {
        // 销毁现有任务栏
        destroyExistingTaskbar();
        // 获取设备配置文件的
        DeviceProfile dp =
                mUserUnlocked ? LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
        // 任务栏是否启用
        boolean isTaskBarEnabled = dp != null && dp.isTaskbarPresent;
        if(dp != null){
            Log.d("yexiao","yexiao"+(dp != null)+"----"+(dp.isTaskbarPresent));
        }
        if (!isTaskBarEnabled) {
            SystemUiProxy.INSTANCE.get(mContext)
                    .notifyTaskbarStatus(/* visible */ false, /* stashed */ false);
            return;
        }
        // TaskbarActivityContext 按钮导航的视图在里面加载,包括那个底部横线也在里面。
        mTaskbarActivityContext = new TaskbarActivityContext(mContext, dp, mNavButtonController,
                mUnfoldProgressProvider);
        // 初始化
        mTaskbarActivityContext.init(mSharedState);
        if (mActivity != null) {
            // 设置相关控制器
            mTaskbarActivityContext.setUIController(
                    createTaskbarUIControllerForActivity(mActivity));
        }
    }

在 TaskbarManager 类中有个 mDispInfoChangeListener 的监听,当导航模式切换时,会在 DisplayController 类中 去回调这里来。

接着往下看TaskbarActivityContext的构造方法:

public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
            TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
            unfoldTransitionProgressProvider) {
        super(windowContext);
        mDeviceProfile = dp.copy(this);
        final Resources resources = getResources();
        mNavMode = DisplayController.getNavigationMode(windowContext);
        mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
        mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
                () -> getPackageManager().isSafeMode());
        mIsUserSetupComplete = SettingsCache.INSTANCE.get(this).getValue(
                Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
        mIsNavBarForceVisible = SettingsCache.INSTANCE.get(this).getValue(
                Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
        mIsNavBarKidsMode = SettingsCache.INSTANCE.get(this).getValue(
                Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
        updateIconSize(resources);
        // 首先获取显示和焦点,因为视图可能会在构造函数中使用它们。
        Display display = windowContext.getDisplay();
        Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
                ? windowContext.getApplicationContext()
                : windowContext.getApplicationContext().createDisplayContext(display);
        mWindowManager = c.getSystemService(WindowManager.class);
        mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
        mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
        // 初始化 views.
        mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(
                R.layout.taskbar, null, false);
        TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
        TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim);
        FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
        StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
        mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
        // 构造控制器 controllers,将会在对应的控制添加对应的图标,以控制逻辑
        mControllers = new TaskbarControllers(this,
                new TaskbarDragController(this),
                buttonController,
                getPackageManager().hasSystemFeature(FEATURE_PC)
                        ? new DesktopNavbarButtonsViewController(this, navButtonsView) :     
                        new NavbarButtonsViewController(this, navButtonsView),
                new RotationButtonController(this,
                        c.getColor(R.color.taskbar_nav_icon_light_color),
                        c.getColor(R.color.taskbar_nav_icon_dark_color),
                        R.drawable.ic_sysbar_rotate_button_ccw_start_0,
                        R.drawable.ic_sysbar_rotate_button_ccw_start_90,
                        R.drawable.ic_sysbar_rotate_button_cw_start_0,
                        R.drawable.ic_sysbar_rotate_button_cw_start_90,
                        () -> getDisplay().getRotation()),
                new TaskbarDragLayerController(this, mDragLayer),
                new TaskbarViewController(this, taskbarView),
                new TaskbarScrimViewController(this, taskbarScrimView),
                new TaskbarUnfoldAnimationController(this, unfoldTransitionProgressProvider,
                        mWindowManager, WindowManagerGlobal.getWindowManagerService()),
                new TaskbarKeyguardController(this),
                new StashedHandleViewController(this, stashedHandleView),
                new TaskbarStashController(this),
                new TaskbarEduController(this),
                new TaskbarAutohideSuspendController(this),
                new TaskbarPopupController(this),
                new TaskbarForceVisibleImmersiveController(this),
                new TaskbarAllAppsController(this, dp),
                new TaskbarInsetsController(this));
    }
    public void init(@NonNull TaskbarSharedState sharedState) {
        mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
        mWindowLayoutParams = createDefaultWindowLayoutParams();
        //  在 TaskbarControllers控制器里,初始化前面构造方法中添加的各种控制器。
        mControllers.init(sharedState);
        updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
        // 生成 LayoutParams 用于将视图作为新窗口直接添加到 WindowManager
        mWindowManager.addView(mDragLayer, mWindowLayoutParams);
    }

这里以 NavbarButtonsViewController 为例子分析:

// NavbarButtonsViewController.java
    /**
     * Initializes the controller
     */
    public void init(TaskbarControllers controllers) {
         // 省略部分代码......
        // 强制导航按钮(特别是后退按钮)在设置向导期间可见。
        boolean isInSetup = !mContext.isUserSetupComplete();
        boolean isInKidsMode = mContext.isNavBarKidsModeActive();
        boolean alwaysShowButtons = isThreeButtonNav || isInSetup;
        // 省略部分代码......
        if (alwaysShowButtons) {
            // 初始化按钮
            initButtons(mNavButtonContainer, mEndContextualContainer,
                    mControllers.navButtonController);
        } else {
        }
        // 省略部分代码......
        mSeparateWindowParent.recreateControllers();
    }
    private void initButtons(ViewGroup navContainer, ViewGroup endContainer,
            TaskbarNavButtonController navButtonController) {
        // back Button
        mBackButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
                mNavButtonContainer, mControllers.navButtonController, R.id.back);
        mBackButtonAlpha = new MultiValueAlpha(mBackButton, NUM_ALPHA_CHANNELS);
        mBackButtonAlpha.setUpdateVisibility(true);
        mPropertyHolders.add(new StatePropertyHolder(
                mBackButtonAlpha.getProperty(ALPHA_INDEX_KEYGUARD_OR_DISABLE),
                flags -> {
                    // Show only if not disabled, and if not on the keyguard or otherwise only when
                    // the bouncer or a lockscreen app is showing above the keyguard
                    boolean showingOnKeyguard = (flags & FLAG_KEYGUARD_VISIBLE) == 0 ||
                            (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0 ||
                            (flags & FLAG_KEYGUARD_OCCLUDED) != 0;
                    return (flags & FLAG_DISABLE_BACK) == 0
                            && ((flags & FLAG_KEYGUARD_VISIBLE) == 0 || showingOnKeyguard);
                }));
        boolean isRtl = Utilities.isRtl(mContext.getResources());
        mPropertyHolders.add(new StatePropertyHolder(mBackButton,
                flags -> (flags & FLAG_IME_VISIBLE) != 0 && !mContext.isNavBarKidsModeActive(),
                View.ROTATION, isRtl ? 90 : -90, 0));
        // Translate back button to be at end/start of other buttons for keyguard
        int navButtonSize = mContext.getResources().getDimensionPixelSize(
                R.dimen.taskbar_nav_buttons_size);
        mPropertyHolders.add(new StatePropertyHolder(
                mBackButton, flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0
                        || (flags & FLAG_KEYGUARD_VISIBLE) != 0,
                VIEW_TRANSLATE_X, navButtonSize * (isRtl ? -2 : 2), 0));
        // home button
        mHomeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, navContainer,
                navButtonController, R.id.home);
        mHomeButtonAlpha = new MultiValueAlpha(mHomeButton, NUM_ALPHA_CHANNELS);
        mHomeButtonAlpha.setUpdateVisibility(true);
        mPropertyHolders.add(
                new StatePropertyHolder(mHomeButtonAlpha.getProperty(
                        ALPHA_INDEX_KEYGUARD_OR_DISABLE),
                flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
                        (flags & FLAG_DISABLE_HOME) == 0));
        // Recents button
        View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
                navContainer, navButtonController, R.id.recent_apps);
        mHitboxExtender.init(recentsButton, mNavButtonsView, mContext.getDeviceProfile(),
                () -> {
                    float[] recentsCoords = new float[2];
                    getDescendantCoordRelativeToAncestor(recentsButton, mNavButtonsView,
                            recentsCoords, false);
                    return recentsCoords;
                }, new Handler());
        recentsButton.setOnClickListener(v -> {
            navButtonController.onButtonClick(BUTTON_RECENTS);
            mHitboxExtender.onRecentsButtonClicked();
        });
        mPropertyHolders.add(new StatePropertyHolder(recentsButton,
                flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 && (flags & FLAG_DISABLE_RECENTS) == 0
                        && !mContext.isNavBarKidsModeActive()));
        // A11y button
        mA11yButton =  (R.drawable.ic_sysbar_accessibility_button, BUTTON_A11Y,
                endContainer, navButtonController, R.id.accessibility_button,
                R.layout.taskbar_contextual_button);
        mPropertyHolders.add(new StatePropertyHolder(mA11yButton,
                flags -> (flags & FLAG_A11Y_VISIBLE) != 0
                        && (flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0));
    }

事件的在 addButton() 的时候直接设置了,而且有特殊需求的,会单独设置。

至此简单分析完成

相关文章
|
3月前
|
Java Android开发
Android面试题经典之Glide取消加载以及线程池优化
Glide通过生命周期管理在`onStop`时暂停请求,`onDestroy`时取消请求,减少资源浪费。在`EngineJob`和`DecodeJob`中使用`cancel`方法标记任务并中断数据获取。当网络请求被取消时,`HttpUrlFetcher`的`cancel`方法设置标志,之后的数据获取会返回`null`,中断加载流程。Glide还使用定制的线程池,如AnimationExecutor、diskCacheExecutor、sourceExecutor和newUnlimitedSourceExecutor,其中某些禁止网络访问,并根据CPU核心数动态调整线程数。
93 2
|
9天前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
讲解Activity的启动流程了,Activity的启动流程相对复杂一下,涉及到了Activity中的生命周期方法,涉及到了Android体系的CS模式,涉及到了Android中进程通讯Binder机制等等, 首先介绍一下Activity,这里引用一下Android guide中对Activity的介绍:
25 4
|
9天前
|
Android开发 开发者
Android面试之Activity启动流程简述
每个Android开发者都熟悉的Activity,但你是否了解它的启动流程呢?本文将带你深入了解。启动流程涉及四个关键角色:Launcher进程、SystemServer的AMS、应用程序的ActivityThread及Zygote进程。核心在于AMS与ActivityThread间的通信。文章详细解析了从Launcher启动Activity的过程,包括通过AIDL获取AMS、Zygote进程启动以及ActivityThread与AMS的通信机制。接着介绍了如何创建Application及Activity的具体步骤。整体流程清晰明了,帮助你更深入理解Activity的工作原理。
16 0
|
2月前
|
Android开发
我的Android进阶修炼:安卓启动流程之init(1)
本文深入分析了Android系统中的init进程,包括其源码结构、主要功能以及启动流程的详细注解,旨在帮助读者理解init作为用户空间的1号进程在Android启动过程中的关键作用。
32 1
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
View的绘制和事件处理是两个重要的主题,上一篇《图解 Android事件分发机制》已经把事件的分发机制讲得比较详细了,这一篇是针对View的绘制,View的绘制如果你有所了解,基本分为measure、layout、draw 过程,其中比较难理解就是measure过程,所以本篇文章大幅笔地分析measure过程,相对讲得比较详细,文章也比较长,如果你对View的绘制还不是很懂,对measure过程掌握得不是很深刻,那么耐心点,看完这篇文章,相信你会有所收获的。
80 2
|
2月前
|
存储 缓存 Java
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
34 0
|
2月前
|
Java Android开发 Kotlin
Android项目架构设计问题之要在Glide库中加载网络图片到ImageView如何解决
Android项目架构设计问题之要在Glide库中加载网络图片到ImageView如何解决
25 0
|
3月前
|
Java Android开发
android 设置系统时间的流程
android 设置系统时间的方法
251 2
|
4月前
|
ARouter IDE 开发工具
Android面试题之App的启动流程和启动速度优化
App启动流程概括: 当用户点击App图标,Launcher通过Binder IPC请求system_server启动Activity。system_server指示Zygote fork新进程,接着App进程向system_server申请启动Activity。经过Binder通信,Activity创建并回调生命周期方法。启动状态分为冷启动、温启动和热启动,其中冷启动耗时最长。优化技巧包括异步初始化、避免主线程I/O、类加载优化和简化布局。
63 3
Android面试题之App的启动流程和启动速度优化
|
4月前
|
安全 网络协议 算法
Android网络基础面试题之HTTPS的工作流程和原理
HTTPS简述 HTTPS基于TCP 443端口,通过CA证书确保服务器身份,使用DH算法协商对称密钥进行加密通信。流程包括TCP握手、证书验证(公钥解密,哈希对比)和数据加密传输(随机数加密,预主密钥,对称加密)。特点是安全但慢,易受特定攻击,且依赖可信的CA。每次请求可能复用Session ID以减少握手。
55 2
下一篇
无影云桌面