接着上一篇RecentsActivity启动分析一继续分析RecentsActivity。先给大家看布局的结构图

简单的画了RecentsView部分,如下图所示

那接着就从RecentsActivity的构造方法开始分析

@Override
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//初始化RecentsTaskLoaderRecentsTaskLoader.initialize(this);//获取SystemServicesProxy的对象SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();mConfig = RecentsConfiguration.reinitialize(this, ssp);// 初始化AppWidgetHostmAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId);//设置布局setContentView(R.layout.recents);//控件初始化mRecentsView = (RecentsView) findViewById(R.id.recents_view);mRecentsView.setCallbacks(this);mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);mDebugOverlayStub = (ViewStub) findViewById(R.id.debug_overlay_stub);mScrimViews = new SystemBarScrimViews(this, mConfig);inflateDebugOverlay();// Bind the search app widget when we first start up//绑定搜索框mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);// Register the broadcast receiver to handle messages when the screen is turned off//注册广播接收器,接收来自系统的广播,处理系统消息IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_SCREEN_OFF);filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);registerReceiver(mSystemBroadcastReceiver, filter);//清除近期应用的按钮ImageButton clearButton = (ImageButton) findViewById(R.id.clear_button);clearButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {new Thread(new Runnable() {@Overridepublic void run() {//清除所有任务removeAllTasks();}}).start();}});am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);pm = getPackageManager();
}

这个函数主要就是初始化控件,注册广播。

onStart()

@Override
protected void onStart() {super.onStart();MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY);//获取RecentsTaskLoader实例RecentsTaskLoader loader = RecentsTaskLoader.getInstance();//获取SystemServiceProxy实例,这个类主要承接了RecentsActivity和系统服务的交互,包含获取最近任务列表,启动制定任务所在的应用等等。 SystemServicesProxy ssp = loader.getSystemServicesProxy();//通知可见性改变Recents.notifyVisibilityChanged(this, ssp, true);//注册广播接收器接收处理来自Service的消息:隐藏、打开Recent Apps界面IntentFilter filter = new IntentFilter();filter.addAction(Recents.ACTION_HIDE_RECENTS_ACTIVITY);filter.addAction(Recents.ACTION_TOGGLE_RECENTS_ACTIVITY);filter.addAction(Recents.ACTION_START_ENTER_ANIMATION);registerReceiver(mServiceBroadcastReceiver, filter);// Register any broadcast receivers for the task loaderloader.registerReceivers(this, mRecentsView);//更新recent tasksupdateRecentsTasks();// If this is a new instance from a configuration change, then we have to manually trigger// the enter animation state, or if recents was relaunched by AM, without going through// the normal mechanismsboolean wasLaunchedByAm = !mConfig.launchedFromHome && !mConfig.launchedFromAppWithThumbnail;if (mConfig.launchedHasConfigurationChanged || wasLaunchedByAm) {onEnterAnimationTriggered();}if (!mConfig.launchedHasConfigurationChanged) {mRecentsView.disableLayersForOneFrame();}
}

重点来看两点:

(1)Recents.notifyVisibilityChanged(this, ssp, true);

既然是Recents类,我们就到该类中寻找这个被调用的函数

/** Notifies the callbacks that the visibility of Recents has changed. */
public static void notifyVisibilityChanged(Context context, SystemServicesProxy ssp,boolean visible) {if (ssp.isForegroundUserOwner()) {visibilityChanged(visible);} else {Intent intent = createLocalBroadcastIntent(context,ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER);intent.putExtra(EXTRA_RECENTS_VISIBILITY, visible);context.sendBroadcastAsUser(intent, UserHandle.OWNER);}
}

调用了sRecentsComponentCallbacks.onVisibilityChanged(visible),RecentsComponent.Callbacks是RecentsComponent的内部接口,由BaseStatusBar类实现,那这样就是调用了BaseAtatusBar类中的onVisibilityChanged函数.

(2)updateRecentsTasks();

/** Updates the set of recent tasks */
void updateRecentsTasks() {// If AlternateRecentsComponent has preloaded a load plan, then use that to prevent// reconstructing the task stackRecentsTaskLoader loader = RecentsTaskLoader.getInstance();RecentsTaskLoadPlan plan = Recents.consumeInstanceLoadPlan();if (plan == null) {//创建加载任务计划plan = loader.createLoadPlan(this);}// Start loading tasks according to the load planif (!plan.hasTasks()) {/*preloadTasks方法中调用了RecentsTaskLoadPlan类的preLoadPlan函数,在该函数中调用preloadRawTask函数继而调用mSystemServicesProxy.getRecentTasks函数得到rawtasks,并不是正在显示的UI,是原始数据配合UI显示*/}RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();loadOpts.runningTaskId = mConfig.launchedToTaskId;loadOpts.numVisibleTasks = mConfig.launchedNumVisibleTasks;loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails;loader.loadTasks(this, plan, loadOpts);ArrayList<TaskStack> stacks = plan.getAllTaskStacks();mConfig.launchedWithNoRecentTasks = !plan.hasTasks();if (!mConfig.launchedWithNoRecentTasks) {mRecentsView.setTaskStacks(stacks);}// Create the home intent runnableIntent homeIntent = new Intent(Intent.ACTION_MAIN, null);homeIntent.addCategory(Intent.CATEGORY_HOME);homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent,ActivityOptions.makeCustomAnimation(this,mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter :R.anim.recents_to_launcher_enter,mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit :R.anim.recents_to_launcher_exit));// Mark the task that is the launch targetint taskStackCount = stacks.size();int launchTaskIndexInStack = 0;if (mConfig.launchedToTaskId != -1) {for (int i = 0; i < taskStackCount; i++) {TaskStack stack = stacks.get(i);ArrayList<Task> tasks = stack.getTasks();int taskCount = tasks.size();for (int j = 0; j < taskCount; j++) {Task t = tasks.get(j);if (t.key.id == mConfig.launchedToTaskId) {t.isLaunchTarget = true;launchTaskIndexInStack = tasks.size() - j - 1;break;}}}}// Update the top level view's visibilitiesif (mConfig.launchedWithNoRecentTasks) {if (mEmptyView == null) {mEmptyView = mEmptyViewStub.inflate();}mEmptyView.setVisibility(View.VISIBLE);mRecentsView.setSearchBarVisibility(View.GONE);} else {if (mEmptyView != null) {mEmptyView.setVisibility(View.GONE);}if (mRecentsView.hasValidSearchBar()) {mRecentsView.setSearchBarVisibility(View.VISIBLE);} else {refreshSearchWidgetView();}}// Animate the SystemUI scrims into viewmScrimViews.prepareEnterRecentsAnimation();……
}

这个函数主要做了三件事:
(1)调用RecentsTaskLoader的loadTasks函数获取相关最近使用应用的相关信息。

/** Begins loading the heavy task data according to the specified options. */
public void loadTasks(Context context, RecentsTaskLoadPlan plan,RecentsTaskLoadPlan.Options opts) {if (opts == null) {throw new RuntimeException("Requires load options");}plan.executePlan(opts, this, mLoadQueue);if (!opts.onlyLoadForCache) {mNumVisibleTasksLoaded = opts.numVisibleTasks;mNumVisibleThumbnailsLoaded = opts.numVisibleTaskThumbnails;// Start the loadermLoader.start(context);}
}

mLoader是RecentsTaskLoader的对象,在它的构造方法中进行一些初始化操作

private RecentsTaskLoader(Context context) {mMaxThumbnailCacheSize = context.getResources().getInteger(R.integer.config_recents_max_thumbnail_count);mMaxIconCacheSize = context.getResources().getInteger(R.integer.config_recents_max_icon_count);int iconCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :mMaxIconCacheSize;int thumbnailCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :mMaxThumbnailCacheSize;// Create the default assetsBitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);icon.eraseColor(0x00000000);mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);mDefaultThumbnail.setHasAlpha(false);mDefaultThumbnail.eraseColor(0xFFffffff);mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);// Initialize the proxy, cache and loadersmSystemServicesProxy = new SystemServicesProxy(context);mPackageMonitor = new RecentsPackageMonitor();mLoadQueue = new TaskResourceLoadQueue();mApplicationIconCache = new DrawableLruCache(iconCacheSize);mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);mActivityLabelCache = new StringLruCache(100);mContentDescriptionCache = new StringLruCache(100);mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache,mDefaultThumbnail, mDefaultApplicationIcon);}

初始化了三个缓存,主要用于缓存应用图标,名称,截屏。mLoadQueue是一个用于缓存任务的队列 。mLoader是
TaskResourceLoader的对象,它的构造函数中启动了一个线程HandlerThread,在它的Run函数中一直循环从mLoadQueue中读取任务并获取任务所对应的截图,并缓存到mThumbnailCache中,然后通知TaskView加载截图并显示。

/** Restarts the loader thread */
void start(Context context) {mContext = context;mCancelled = false;mSystemServicesProxy = new SystemServicesProxy(context);// Notify the load thread to start loadingsynchronized(mLoadThread) {mLoadThread.notifyAll();}
}
@Override
public void run() {while (true) {if (mCancelled) {// We have to unset the context here, since the background thread may be using it// when we call stop()mContext = null;// If we are cancelled, then wait until we are started againsynchronized(mLoadThread) {try {mLoadThread.wait();} catch (InterruptedException ie) {ie.printStackTrace();}}} else {RecentsConfiguration config = RecentsConfiguration.getInstance();SystemServicesProxy ssp = mSystemServicesProxy;// If we've stopped the loader, then fall through to the above logic to wait on// the load threadif (ssp != null) {// Load the next item from the queuefinal Task t = mLoadQueue.nextTask();if (t != null) {Drawable cachedIcon = mApplicationIconCache.get(t.key);Bitmap cachedThumbnail = mThumbnailCache.get(t.key);……if (!mCancelled) {// Notify that the task data has changedfinal Drawable newIcon = cachedIcon;final Bitmap newThumbnail = cachedThumbnail == mDefaultThumbnail? null : cachedThumbnail;mMainThreadHandler.post(new Runnable() {@Overridepublic void run() {t.notifyTaskDataLoaded(newThumbnail, newIcon);}});}}}……}}
}

t是Task类的对象,调用notifyTaskDataLoaded的函数中最终调用mCb.onTaskDataLoaded函数,mCb是Task.TaskCallbacks内部接口类的对象,而TaskView实现了这个接口,也就是调用用TaskView中的onTaskDataLoaded函数。

@Override
public void onTaskDataLoaded() {if (mThumbnailView != null && mHeaderView != null) {// Bind each of the views to the new task datamThumbnailView.rebindToTask(mTask);mHeaderView.rebindToTask(mTask);// Rebind any listenersAccessibilityManager am = (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);if (Constants.DebugFlags.App.EnableTaskFiltering || (am != null && am.isEnabled())) {mHeaderView.mApplicationIcon.setOnClickListener(this);}mHeaderView.mDismissButton.setOnClickListener(this);if (mConfig.multiStackEnabled) {mHeaderView.mMoveTaskButton.setOnClickListener(this);}mActionButtonView.setOnClickListener(this);mHeaderView.mApplicationIcon.setOnLongClickListener(this);}mTaskDataLoaded = true;
}

(2)调用mRecentsView.setTaskStacks,把获得的TaskStack设置到RecentsView中创建TaskStackView

public void setTaskStacks(ArrayList<TaskStack> stacks) {……for (int i = mTaskStackViews.size(); i < numStacks; i++) {TaskStack stack = stacks.get(i);TaskStackView stackView = new TaskStackView(getContext(), stack);stackView.setCallbacks(this);addView(stackView);mTaskStackViews.add(stackView);}……
}

(3)如果没有最近使用的应用信息则显示空的提示信息,如果有就隐藏显示应用信息。

阅读代码前给自己留了个小问题:不显示Recent Apps界面上方的搜索框,当然这个问题很简单,直接在onCreate()函数中将 mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);这个语句注释掉即可,这个语句就是负责搜索框的绑定。

RecentsActivity的分析就到这里结束了,刚接触源码不久,所以只做了简单分析,记录学习的过程,有问题的话欢迎一起讨论。有时间的话我会补上时序图,毕竟看图便可一目了然。

RecentsActivity启动分析二相关推荐

  1. 【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  2. 联盛德 HLK-W801(二):SDK启动分析

    联盛德 HLK-W801(二):SDK启动分析 声明:这是学习的时候记录的笔记,可能存在错误,另外我有一篇针对这个开发板打开串口复位问题进行了硬件修改,相关问题请看我的另一篇博客 文章目录 联盛德 H ...

  3. 【Android 性能优化】应用启动优化 ( 安卓应用启动分析 | Launcher 应用启用普通安卓应用 | 应用进程分析 )

    文章目录 一. Launcher 应用 startActivitySafely 方法分析 二. Launcher 中的 startActivity(View v, Intent intent, Obj ...

  4. ADS中startup.s文件启动分析

    映像文件分析,ADS 中startup.s 文件启动分析,学嵌入式开发ADS 必看 2010-04-17 10:21 声明: 我也是转来的,不是原创,由于别人是网易的日志,不能直接转,所以-- 感谢原 ...

  5. SpringBoot源码分析(二)之自动装配demo

    SpringBoot源码分析(二)之自动装配demo 文章目录 SpringBoot源码分析(二)之自动装配demo 前言 一.创建RedissonTemplate的Maven服务 二.创建测试服务 ...

  6. BSP板机支持包、linux启动分析、ARM裸机编程

    文章目录 一.BSP 二.驱动 驱动的基本要素 三.启动分析 1.uboot 2.uboot的作用 3.uboot相关命令 关键的内容: 1)bootargs,启动参数 2)启动命令 3)修改启动延时 ...

  7. 内核启动分析(三)——zImage 解压缩阶段

          在上阶段,主要是U-BOOT 向内核传递一些参数.而这些参数是通过 struct tag来传递的.U-boot 把要传递给 kernel 的东西保存在 struct tag 数据结构中,启 ...

  8. Android Q 10.1 KeyMaster源码分析(二) - 各家方案的实现

    写在之前 这两篇文章是我2021年3月初看KeyMaster的笔记,本来打算等分析完KeyMaster和KeyStore以后再一起做成一系列贴出来,后来KeyStore的分析中断了,这一系列的文章就变 ...

  9. 威海二职工业机器人专业_工业机器人专业介绍和前景分析二

    原标题:工业机器人专业介绍和前景分析二 人才需求最旺最热门专业-工业机器人技术专业 工业机器人技术专业是经教育部批准成立的热点技术专业,.专业以"国家高职高专精品专业.国家示范高职的重点建设 ...

最新文章

  1. centos下为firefox安装flash插件的几种方法
  2. 工作进度总结汇报01
  3. 贝叶斯学习举例--学习分类文本
  4. Qt 自定义动画属性 QPropertyAnimation
  5. Android Activity动画属性简介
  6. 【数据库系统概论】考研附加部分重点分析【附加】
  7. 06_Influxdb+Grafana绘图基础
  8. qq浏览器网页翻译_如何通过Edge浏览器调用“谷歌翻译”,将整个网页翻译为中文...
  9. mysql查询月份1到31_mysql查询今天、昨天、7天、近30天、本月、上一月 数据
  10. 操作Visual Studio 2010中的SQL Server数据库比较工具
  11. android studio调整字体大小,如何在Android Studio中增加字体大小?
  12. 草根创新的狂欢——《大数据时代》对程序员的启示
  13. python读二进制文件遍历_使用python反向读取二进制文件
  14. [日更-2019.4.20、21] cm-14.1 Android系统启动过程分析(二)-Zygote进程启动过程
  15. windows的hosts文件位置
  16. DevOps自动化测试的原则和实践
  17. 大学生创新工作室阶段性总结
  18. 联发科p60和骁龙710哪个好_骁龙710、麒麟710和联发科P60哪个好 性能对比测试 (全文)...
  19. mysql中日期相减_非凡教育教你excel怎么计算两个日期天数差和时间差
  20. tensorflow频域操作及梯度求取

热门文章

  1. Luma推出分布式路由器,哪里有WIFI死角放哪里
  2. DHCP与DHCP中继
  3. ae显示不能动态链接服务器,ae pr如何联动、建立动态链接?
  4. ACLSCO链路介绍
  5. 腾讯人口密度热力图_从腾讯位置大数据看中国的超级城市,你所处位置是不是很亮?...
  6. FPGA的PS还有什么PL是什么意思
  7. 阿里云面经之实习二面
  8. [学习笔记]使用GNU Toolchain在STM32上跑起一个最小OS
  9. AutoJs学习-2048全自动
  10. 这款录屏神器在 GitHub 火了,秒杀 33 种同类工具!