Android10.0 最近任务Recents功能分析

在Android10.0上,Recents功能分布在SystemUI和Launcher3里面集成.

一.初始化

跟Android8.1类似,先看初始化入口:

1.Recents.java

Recents继承SystemUI,进程启动后会在Dependency里面通过@Inject进行初始化,然后在SystemUIService里面调用SystemUIApplication的startServicesIfNeeded()里面进行启动:
frameworks/base/packages/SystemUI/src/com/android/systemui/recents/Recents.java

java 复制代码
private final RecentsImplementation mImpl
@Override
public void start() {
    //加入callback
    mCommandQueue.addCallback(this);
    mImpl.onStart(mContext);
}

RecentsImplementation替代了之前的RecentsImpl,是一个interface,由其实现类OverviewProxyRecentsImpl来执行操作,关于该类的实例化用到了dagger2,不懂的同学可以去学习一下;

2.OverviewProxyRecentsImpl.java

frameworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java

java 复制代码
private OverviewProxyService mOverviewProxyService;
@Override
public void onStart(Context context) {
   
    mOverviewProxyService = Dependency.get(OverviewProxyService.class);
}

根据调用关系,在onStart()里面创建了OverviewProxyService对象,看一下具体实现:

3.OverviewProxyService.java

中间类,在该类内部去绑定远端的service:
frameworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java

java 复制代码
@Inject
public OverviewProxyService(Context context, CommandQueue commandQueue,
            NavigationBarController navBarController, NavigationModeController navModeController,
            NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
            PipUI pipUI, Optional<Divider> dividerOptional,
            Optional<Lazy<StatusBar>> statusBarOptionalLazy,
            BroadcastDispatcher broadcastDispatcher) {
    super(broadcastDispatcher);
    mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
            com.android.internal.R.string.config_recentsComponentName));
    mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
            .setPackage(mRecentsComponentName.getPackageName());
   
    // Connect to the service
    updateEnabledState();
    startConnectionToCurrentUser();
}
java 复制代码
public void startConnectionToCurrentUser() {
    if (mHandler.getLooper() != Looper.myLooper()) {
        mHandler.post(mConnectionRunnable);
    } else {
        internalConnectToCurrentUser();
    }
}
java 复制代码
private void internalConnectToCurrentUser() {
    
    Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
                .setPackage(mRecentsComponentName.getPackageName());
    try {
        mBound = mContext.bindServiceAsUser(launcherServiceIntent,
                    mOverviewServiceConnection,
                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                    UserHandle.of(getCurrentUserId()));
        }
    
}
java 复制代码
private IOverviewProxy mOverviewProxy;
private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
      
        mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
       
    }
}

跟随调用关系来看,在构造方法内部,会去执行startConnectionToCurrentUser来调用bindServiceAsUser()去启动service,在onServiceConnected中,通过IOverviewProxy.Stub.asInterface(service)来获取IOverviewProxy实例,后续会用到;

Service对应的Intent为android.intent.action.QUICKSTEP_SERVICE,R.string.config_recentsComponentName对应如下,用来获取远端服务的应用包名:

xml 复制代码
<string name="config_recentsComponentName" translatable="false"
        >com.android.launcher3/com.android.quickstep.RecentsActivity</string>

从ComponentName可以看到,被bind的service是在Launcher3里面,接下来一起看一下对应的远端Service;

4.TouchInteractionService.java

packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java

Launcher3内的入口类,通过该类来调用相关逻辑:

java 复制代码
private final IBinder mMyBinder = new IOverviewProxy.Stub() {
   
    @BinderThread
    @Override
    public void onOverviewToggle() {
        mOverviewCommandHelper.onOverviewToggle();
    }
   
}
@Override
public IBinder onBind(Intent intent) {
    return mMyBinder;
}

可以看到,TouchInteractionService里面创建了IOverviewProxy.Stub实例,然后在onBind()返回;

TouchInteractionService是一个Service,在onCreate()里面进行了一些初始化相关的调用:

java 复制代码
@Override
public void onCreate() {
    super.onCreate();
   
    mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
   
    sConnected = true;
}
@UiThread
public void onUserUnlocked() {
   
    mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
    mOverviewCommandHelper = new OverviewCommandHelper(this, mDeviceState,
                mOverviewComponentObserver);
   
}

可以看到,在TouchInteractionService启动后,会创建OverviewComponentObserver实例和OverviewCommandHelper实例,一起看一下这两个类的实现:

5.OverviewComponentObserver.java

packages/apps/Launcher3/quickstep/src/com/android/quickstep/OverviewComponentObserver.java

java 复制代码
public OverviewComponentObserver(Context context, RecentsAnimationDeviceState deviceState) {
    
    ComponentName fallbackComponent = new ComponentName(mContext, RecentsActivity.class);
    mFallbackIntent = new Intent(Intent.ACTION_MAIN)
                .addCategory(Intent.CATEGORY_DEFAULT)
                .setComponent(fallbackComponent)
                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    
    updateOverviewTargets();
}

可以看到,在构造方法内部会创建mFallbackIntent,从组成来看,通过该Intent启动RecentsActivity;接下来看一下 updateOverviewTargets():

java 复制代码
private void updateOverviewTargets() {
   
    mActivityInterface = FallbackActivityInterface.INSTANCE;
    mIsHomeAndOverviewSame = false;
    mOverviewIntent = mFallbackIntent;
   
}

在该方法内部,会将mFallbackIntent赋值给mOverviewIntent,后续启动Recents会用到mOverviewIntent;

6.OverviewCommandHelper.java

packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java

启动Recents的直接入口类,最终实现了onOverviewToggle():

java 复制代码
public OverviewCommandHelper(Context context, RecentsAnimationDeviceState deviceState,
            OverviewComponentObserver observer) {
    
    mRecentsModel = RecentsModel.INSTANCE.get(mContext);
    mOverviewComponentObserver = observer;
}
@BinderThread
public void onOverviewToggle() {
   
    ActivityManagerWrapper.getInstance()
                .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
    MAIN_EXECUTOR.execute(new RecentsActivityCommand<>());
}

以上就是Recents功能在初始化过程中涉及到的关键类,用一张流程图总结一下:

二.启动

前面分析了初始化涉及到的关键类,系统启动后会启动SystemUI进程,然后进行一系列初始化,接下来看一下进入Recents的流程:

关于手势或Key按键触发这一块逻辑处理跟Android8.1处理是一样的,入口都是在PhoneWindowManager,咱们从Recents接收toggleRecentApps()分析:

1.Recents.java

frameworks/base/packages/SystemUI/src/com/android/systemui/recents/Recents.java

java 复制代码
@Override
public void toggleRecentApps() {
   
    mImpl.toggleRecentApps();
}

2.OverviewProxyRecentsImpl.java

frameworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java

java 复制代码
@Override
public void toggleRecentApps() {
    // If connected to launcher service, let it handle the toggle logic
    IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
    if (overviewProxy != null) {
        final Runnable toggleRecents = () -> {
            try {
                if (mOverviewProxyService.getProxy() != null) {
                    mOverviewProxyService.getProxy().onOverviewToggle();
                    mOverviewProxyService.notifyToggleRecentApps();
                }
            } catch (RemoteException e) {
                Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
            }
        };
        //启动runnable
    }
}

在runnable内部会通过OverviewProxyService的getProxy()来获取到Launcher3端实现的IOveriewProxy对象引用,然后调用onOverviewToggle()方法:

3.TouchInteractionService.java

packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java

java 复制代码
@BinderThread
@Override
public void onOverviewToggle() {
    mOverviewCommandHelper.onOverviewToggle();
}

4.OverviewCommandHelper.java

packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java

java 复制代码
@BinderThread
public void onOverviewToggle() {
   ActivityManagerWrapper.getInstance()
                .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
   MAIN_EXECUTOR.execute(new RecentsActivityCommand<>());
}

可以看到,在执行onOverviewToggle()后,实际上是通过Executoe执行了RecentsActivityCommand:

java 复制代码
private class RecentsActivityCommand<T extends StatefulActivity<?>> implements Runnable {
  
    public RecentsActivityCommand() {
        mActivityInterface = mOverviewComponentObserver.getActivityInterface();
      
        //预加载,Android8.1也有相同的逻辑
        mRecentsModel.getTasks(null);
    }
    @Override
     public void run() {
         
         // Otherwise, start overview.
         mListener = mActivityInterface.createActivityInitListener(this::onActivityReady);
         mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(),
                    new RemoteAnimationProvider() {
                        @Override
                        public AnimatorSet createWindowAnimation(
                                RemoteAnimationTargetCompat[] appTargets,
                                RemoteAnimationTargetCompat[] wallpaperTargets) {
                            return RecentsActivityCommand.this.createWindowAnimation(appTargets,
                                    wallpaperTargets);
                        }
                    }, mContext, MAIN_EXECUTOR.getHandler(),
                    mAnimationProvider.getRecentsLaunchDuration());
        }

可以看到,最终是通过registerAndStartActivity()来启动了intent,前面分析到mOverviewComponentObserver.getOverviewIntent()对应的就是mFallbackIntent,最终启动了RecentsActivity;

用一张流程图总结一下:

三.显示

在启动RecentsActivity后,会显示最近任务列表,看一下具体工作流程:

1.RecentsActivity.java

frameworks/base/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java

Recents显示Activity

java 复制代码
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
  
    setupViews();
   
}
protected void setupViews() {
    inflateRootView(R.layout.fallback_recents_activity);
    setContentView(getRootView());
    mDragLayer = findViewById(R.id.drag_layer);
    mFallbackRecentsView = findViewById(R.id.overview_panel);
    mActionsView = findViewById(R.id.overview_actions_view);
    mDragLayer.recreateControllers();
    mFallbackRecentsView.init(mActionsView);
}

RecentsActivity继承了StatefulActivity,有些方法实现是在父类里面执行的,在onCreate()里面执行setupViews(),初始化了FallbackRecentsView,FallbackRecentsView继承了RecentsView,主要逻辑都是在RecentsView里面实现的,直接看RecentsView的实现逻辑:

2.RecentsView.java

frameworks/base/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java

Recents显示主View

java 复制代码
public RecentsView(Context context, AttributeSet attrs, int defStyleAttr,
            BaseActivityInterface sizeStrategy) {
    super(context, attrs, defStyleAttr);
    
    mModel = RecentsModel.INSTANCE.get(context);
    mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
                .inflate(R.layout.overview_clear_all_button, this, false);
    mClearAllButton.setOnClickListener(this::dismissAllTasks);
    mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
                10 /* initial size */);
   
}

可以看到,在构造方法内部,获取了RecentsModel实例,创建了ViewPool实例mTaskViewPool,该mTaskViewPool存储TaskView,对应的layout为 R.layout.task,最大数量为20;

java 复制代码
@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    updateTaskStackListenerState();
    ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
    //当snapshot更新时,会进行回调刷新UI
    RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
}

在RecentsView显示时会回调onAttachedToWindow(),在内部执行了updateTaskStackListenerState(),然后做了一些注册回调操作,当有变化时,会进行回调通知来更新UI;

java 复制代码
private void updateTaskStackListenerState() {
    boolean handleTaskStackChanges = mOverviewStateEnabled && isAttachedToWindow()
                && getWindowVisibility() == VISIBLE;
    if (handleTaskStackChanges != mHandleTaskStackChanges) {
        mHandleTaskStackChanges = handleTaskStackChanges;
        if (handleTaskStackChanges) {
            reloadIfNeeded();
        }
    }
}

在updateTaskStackListenerState()内部会进行一系列条件判断来确定是否执行reloadIfNeeded(),当首次进入时会执行reloadIfNeeded():

java 复制代码
public void reloadIfNeeded() {
    if (!mModel.isTaskListValid(mTaskListChangeId)) {
        mTaskListChangeId = mModel.getTasks(this::applyLoadPlan);
    }
}

通过RecentsModel的getTasks()来获取任务列表,然后回到applyLoadPlan(),getTasks()逻辑在后面进行分析,先看一下applyLoadPlan()方法的执行逻辑:

java 复制代码
protected void applyLoadPlan(ArrayList<Task> tasks) {
    // Unload existing visible task data
    unloadVisibleTaskData();
    final int requiredTaskCount = tasks.size();
    if (getTaskViewCount() != requiredTaskCount) {
        for (int i = getTaskViewCount(); i < requiredTaskCount; i++) {
            addView(mTaskViewPool.getView());
        }
        if (requiredTaskCount > 0) {
            addView(mClearAllButton);
        }
    }
    // Rebind and reset all task views
    for (int i = requiredTaskCount - 1; i >= 0; i--) {
        final int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex;
        final Task task = tasks.get(i);
        final TaskView taskView = (TaskView) getChildAt(pageIndex);
        taskView.bind(task, mOrientationState);
    }
    resetTaskVisuals();
}

在applyLoadPlan()内部,主要执行了四项工作:

  1. unloadVisibleTaskData():将现有visible的task数据进行置空;
  2. 根据task数量(首次进入)进行addView,TaskView通过mTaskViewPool的getView()进行获取,最后添加clearAllButton;
  3. 对添加完的TaskView进行bind()操作,将对应的task存在TaskView内部,类似setTag()功能;
  4. 执行resetTaskVisuals()来刷新加载数据;
java 复制代码
public void resetTaskVisuals() {
    // Update the set of visible task's data
    loadVisibleTaskData();
}
public void loadVisibleTaskData() {
    // Update the task data for the in/visible children
    for (int i = 0; i < getTaskViewCount(); i++) {
        TaskView taskView = getTaskViewAt(i);
        Task task = taskView.getTask();
         int index = indexOfChild(taskView);
         boolean visible = lower <= index && index <= upper;
         if (visible) {
             if (task == mTmpRunningTask) {
                // Skip loading if this is the task that we are animating into
                 continue;
             }
             if (!mHasVisibleTaskData.get(task.key.id)) {
                 taskView.onTaskListVisibilityChanged(true /* visible */);
             }
             mHasVisibleTaskData.put(task.key.id, visible);
         }
    }
}

最终在loadVisibleTaskData()里面通过TaskView的onTaskVisibilityChanged(true)来加载数据;

3.TaskView.java

Recents列表中Task对应的显示View
frameworks/base/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskView.java

java 复制代码
public void bind(Task task, RecentsOrientedState orientedState) {
    mTask = task;
    mSnapshotView.bind(task);
}
java 复制代码
public void onTaskListVisibilityChanged(boolean visible) {
    if (mTask == null) {
        return;
    }
        cancelPendingLoadTasks();
    if (visible) {
        // These calls are no-ops if the data is already loaded, try and load the high
        // resolution thumbnail if the state permits
        RecentsModel model = RecentsModel.INSTANCE.get(getContext());
        TaskThumbnailCache thumbnailCache = model.getThumbnailCache();
        TaskIconCache iconCache = model.getIconCache();
        mThumbnailLoadRequest = thumbnailCache.updateThumbnailInBackground(
                    mTask, thumbnail -> mSnapshotView.setThumbnail(mTask, thumbnail));
        mIconLoadRequest = iconCache.updateIconInBackground(mTask,
                    (task) -> {
                        setIcon(task.icon);
                        if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
                            getRecentsView().updateLiveTileIcon(task.icon);
                        }
                        mDigitalWellBeingToast.initialize(mTask);
                    });
        } else {
            mSnapshotView.setThumbnail(null, null);
            setIcon(null);
            // Reset the task thumbnail reference as well (it will be fetched from the cache or
            // reloaded next time we need it)
            mTask.thumbnail = null;
        }
}

在onTaskListVisibilityChanged()内部,当visible为true时,执行mSnapshotView.setThumbnail()和setIcon()分别来加载缩略图和icon;当visible为false时,将其置空;

java 复制代码
public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    setOnClickListener((view) -> {
         if (getTask() == null) {
             return;
         }
         launchTask(true /* animate */);
        });
}
public void launchTask(boolean animate) {
    launchTask(animate, false /* freezeTaskList */);
}
private void launchTaskInternal(boolean animate, boolean freezeTaskList,
            Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
    if (mTask != null) {
        ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key,
                    opts, resultCallback, resultCallbackHandler);
        getRecentsView().onTaskLaunched(mTask);
    }
}

在TaskView内部设置了点击事件监听,当点击后会执行launchTask,最终会调用到ActivityManagerWrapper的startActivityFromRecentsAsync()来快速切换到对应的任务;

4.RecentsModel.java

Recents数据获取功能管理类
packages/apps/Launcher3/quickstep/src/com/android/quickstep/RecentsModel.java

java 复制代码
private RecentsModel(Context context) {
    mContext = context;
    mTaskList = new RecentTasksList(MAIN_EXECUTOR,
                new KeyguardManagerCompat(context), ActivityManagerWrapper.getInstance());
    mIconCache = new TaskIconCache(context, looper);
    mThumbnailCache = new TaskThumbnailCache(context, looper);
   ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
}
java 复制代码
RecentsModel继承了TaskStackChangeListener,在构造方法内部初始化了RecentsTaskList、TaskIconCache和TaskThumbnailCache实例,注册了registerTaskStackListener回调;分别来获取最近任务列表、获取Task对应的Icon和,
   RecentsTaskList:获取最近任务列表;
   TaskIconCache:获取Task对应的icon,并进行缓存;
   TaskThumbnailCache:获取Task对应的thumbnailData,并进行缓存;
   与Android8.1不同的是,8.1上在获取最近任务列表后会获取任务对应的Thumbnail和Icon,最终封装成Task,在显示时直接通过Task.thumbnail和Task.icon就可以直接显示;11上会通过TaskIconCache和TaskThumbnailCache进行分别存储管理,首次显示或有新的任务,需要通过TaskIconCache和TaskThumbnailCache执行对应的request去获取并进行cache存储;
java 复制代码
public int getTasks(Consumer<ArrayList<Task>> callback) {
    return mTaskList.getTasks(false /* loadKeysOnly */, callback);
}

执行getTasks时,实际是通过RecentsTaskList的getTasks()来执行的;

java 复制代码
@Override
public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
    mThumbnailCache.updateTaskSnapShot(taskId, snapshot);
    for (int i = mThumbnailChangeListeners.size() - 1; i >= 0; i--) {
        Task task = mThumbnailChangeListeners.get(i).onTaskThumbnailChanged(taskId, snapshot);
        if (task != null) {
            task.thumbnail = snapshot;
        }
    }
}

当Task的snapshot截取完毕后,会收到onTaskSnapshotChanged()回调,先对snapshot进行缓存,然后执行onTaskThumbnailChanged()通知,在RecentsView里面对thumbnail进行更新;

5.RecentsTaskList.java

获取最近任务列表类

java 复制代码
public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<Task>> callback) {
    // Kick off task loading in the background
    UI_HELPER_EXECUTOR.execute(() -> {
       if (!mResultsBg.isValidForRequest(requestLoadId, loadKeysOnly)) {
            mResultsBg = loadTasksInBackground(Integer.MAX_VALUE, requestLoadId, loadKeysOnly);
       }
       TaskLoadResult loadResult = mResultsBg;
       mMainThreadExecutor.execute(() -> {
           mResultsUi = loadResult;
           if (callback != null) {
               ArrayList<Task> result = copyOf(mResultsUi);
               callback.accept(result);
           }
      });
    });
   return requestLoadId;
}

在getTasks()内部通过loadTasksInBackgroud()来获取TaskLoadResult对象mResultsBg,然后在主线程里面进行回调,最终执行到RecentsView里面的applyLoadPlan()是在主线程里面刷新UI;先看一下loadTasksInBackground()方法:

java 复制代码
TaskLoadResult loadTasksInBackground(int numTasks, int requestId, boolean loadKeysOnly) {
    int currentUserId = Process.myUserHandle().getIdentifier();
    List<ActivityManager.RecentTaskInfo> rawTasks =
                mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId);
    // The raw tasks are given in most-recent to least-recent order, we need to reverse it
    Collections.reverse(rawTasks);
    TaskLoadResult allTasks = new TaskLoadResult(requestId, loadKeysOnly, rawTasks.size());
    for (ActivityManager.RecentTaskInfo rawTask : rawTasks) {
        Task.TaskKey taskKey = new Task.TaskKey(rawTask);
        Task task;
        if (!loadKeysOnly) {
            boolean isLocked = tmpLockedUsers.get(taskKey.userId);
            task = Task.from(taskKey, rawTask, isLocked);
        } else {
            task = new Task(taskKey);
        }
        allTasks.add(task);
    }
    return allTasks;
}

可以看到,在loadTasksInBackgroud()内部,通过ActivityManagerWrapper的getRecentTasks()来获取rawTasks,然后反向排序,最后将其处理添加到allTasks,然后返回结果;

6.ActivityManagerWrapper.java

SystemUI与SystemServer交互类
frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java

java 复制代码
public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
    try {
       return ActivityTaskManager.getService().getRecentTasks(numTasks,RECENT_IGNORE_UNAVAILABLE, userId).getList();
    }
}
public @NonNull ThumbnailData getTaskThumbnail(int taskId, boolean isLowResolution) {
    ActivityManager.TaskSnapshot snapshot = null;
    try {
        snapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId, isLowResolution);
    } catch (RemoteException e) {
        Log.w(TAG, "Failed to retrieve task snapshot", e);
    }
    if (snapshot != null) {
        return new ThumbnailData(snapshot);
    } else {
        return new ThumbnailData();
    }
}
public boolean startActivityFromRecents(int taskId, ActivityOptions options) {
    try {
        Bundle optsBundle = options == null ? null : options.toBundle();
        ActivityTaskManager.getService().startActivityFromRecents(taskId, optsBundle);
        return true;
    } catch (Exception e) {
        return false;
    }
 }

ActivityManagerWrapper提供了跟systemserver交互的接口,相当于Android8.1中的SystemServicesProxy功能;

用一张流程图总结显示过程:

以上就是对Android10.0 Recents功能的分析,功能实现由之前一个进程拆分到两个进程,其他处理基本上保持一致。

👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀

相关推荐
老哥不老1 小时前
MySQL安装教程
android·mysql·adb
xcLeigh2 小时前
html实现好看的多种风格手风琴折叠菜单效果合集(附源码)
android·java·html
图王大胜3 小时前
Android SystemUI组件(07)锁屏KeyguardViewMediator分析
android·framework·systemui·锁屏
InsightAndroid3 小时前
Android通知服务及相关概念
android
aqi005 小时前
FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
android·ffmpeg·音视频·直播·流媒体
Leoysq5 小时前
Unity实现原始的发射子弹效果
android
起司锅仔5 小时前
ActivityManagerService Activity的启动流程(2)
android·安卓
猿小蔡5 小时前
Android Bitmap 和Drawable的区别
android
峥嵘life5 小时前
Android14 手机蓝牙配对后阻塞问题解决
android·智能手机
猿小蔡5 小时前
Android混淆不要怕--一文搞定
android