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

Android10.0 最近任务Recents功能分析在 Android10 0 上 Recents 功能分布在 SystemUI 和 Launcher3 里面集成 android 最近任务

大家好,欢迎来到IT知识分享网。

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

一.初始化

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

1.Recents.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

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

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

3.OverviewProxyService.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(); } 
public void startConnectionToCurrentUser() { 
    if (mHandler.getLooper() != Looper.myLooper()) { 
    mHandler.post(mConnectionRunnable); } else { 
    internalConnectToCurrentUser(); } } 
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())); } } 
private IOverviewProxy mOverviewProxy; private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() { 
    @Override public void onServiceConnected(ComponentName name, IBinder service) { 
    mOverviewProxy = IOverviewProxy.Stub.asInterface(service); } } 
<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内的入口类,通过该类来调用相关逻辑:

private final IBinder mMyBinder = new IOverviewProxy.Stub() { 
    @BinderThread @Override public void onOverviewToggle() { 
    mOverviewCommandHelper.onOverviewToggle(); } } @Override public IBinder onBind(Intent intent) { 
    return mMyBinder; } 
@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

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():

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():

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功能在初始化过程中涉及到的关键类,用一张流程图总结一下:

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

二.启动

1.Recents.java

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

@Override public void toggleRecentApps() { 
    mImpl.toggleRecentApps(); } 
2.OverviewProxyRecentsImpl.java

frameworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.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

@BinderThread @Override public void onOverviewToggle() { 
    mOverviewCommandHelper.onOverviewToggle(); } 
4.OverviewCommandHelper.java

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

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

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

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()); } 

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

三.显示

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

1.RecentsActivity.java

frameworks/base/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java
Recents显示Activity

@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

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;

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

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

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

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

public void reloadIfNeeded() { 
    if (!mModel.isTaskListValid(mTaskListChangeId)) { 
    mTaskListChangeId = mModel.getTasks(this::applyLoadPlan); } } 

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

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()来刷新加载数据;
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
public void bind(Task task, RecentsOrientedState orientedState) { 
    mTask = task; mSnapshotView.bind(task); } 
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时,将其置空;

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
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); } 
RecentsModel继承了TaskStackChangeListener,在构造方法内部初始化了RecentsTaskListTaskIconCacheTaskThumbnailCache实例,注册了registerTaskStackListener回调;分别来获取最近任务列表、获取Task对应的Icon和, RecentsTaskList:获取最近任务列表; TaskIconCache:获取Task对应的icon,并进行缓存; TaskThumbnailCache:获取Task对应的thumbnailData,并进行缓存; 与Android8.1不同的是,8.1上在获取最近任务列表后会获取任务对应的ThumbnailIcon,最终封装成Task,在显示时直接通过Task.thumbnail和Task.icon就可以直接显示;11上会通过TaskIconCacheTaskThumbnailCache进行分别存储管理,首次显示或有新的任务,需要通过TaskIconCacheTaskThumbnailCache执行对应的request去获取并进行cache存储; 
public int getTasks(Consumer<ArrayList<Task>> callback) { 
    return mTaskList.getTasks(false /* loadKeysOnly */, callback); } 

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

@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

获取最近任务列表类

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()方法:

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
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; } } 

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

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/117762.html

(0)
上一篇 2025-11-18 14:20
下一篇 2025-11-18 14:33

相关推荐

发表回复

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

关注微信