Launcher3-桌面布局+主要的类+启动流程

article/2025/11/7 3:16:24

    • 一、launhcer3桌面布局
    • 二、launcher3主要的类
          • LauncherModel:
          • BubblTextView:
          • DragController:
          • LauncherAppState:
          • DragView:
          • DragSource,DropTarget:
          • Folder:
          • FolderIcon:
          • LauncherProvider:
          • ItemInfo:
          • LauncherProvider:
          • LauncherSettings:
          • DatabaseHelper:
    • 三、细说ItemInfo
    • 四、Launcher3启动流程

一、launhcer3桌面布局

在这里插入图片描述

二、launcher3主要的类

LauncherModel:

跟数据有关系,保存了桌面运行时的状态信息,也提供了读写数据库的API,他有一个内部类LoaderTask,桌面启动从数据库中读取数据并把图标和小工具添加上去的时候用的就是他。

BubblTextView:

图标都是基于他,不过奇怪的是,他是继承自TextView

DragController:

DragLayer只是一个ViewGroup,具体的拖拽的处理都放到了DragController中。

LauncherAppState:

单例模式,主要在启动的时候用,他初始化了一些对象,并且注册了广播监听器和ContentObserver。

DragView:

在拖动图标的时候跟随手指移动的View就是他。

DragSource,DropTarget:

跟拖拽相关的接口,DragSource表示图标从哪里被拖出来,DropTarget表示图标可以被拖到哪里去。

Folder:

文件夹打开时候那个view。

FolderIcon:

文件夹图标。

LauncherProvider:

数据库类,Launcher3使用了SQLite,数据库文件保存在/data/data/包名/databases/launcher.db 下,有兴趣的同学可以把这个东西拷贝出来,用SQLite的工具看看里面都是怎么保存的。

ItemInfo:

运行时保存了桌面上每个项目的信息,包括图标在第几屏,第几行第几列,高度宽度等信息,每一个ItemInfo对象都对应着数据库中的一条记录。在Launcher3源码路径下,会有很多以Info结尾的类,这些类都是ItemInfo的子类,具体代表了桌面上的某个项目。比如说FolderIcon和FolderInfo是对应的,BubbleTextView和ShortcutInfo是对应的,AppWidgetHostView和LauncherAppWidgetInfo是对应的。有了对应关系,可以这样通过view获取ItemInfo对象:
ItemInfo info = (ItemInfo)bubbletextview.getTag();
这样这里的info其实就是ShortcutInfo对象了。

LauncherProvider:

桌面信息的ContentProvider。

LauncherSettings:

存了数据库相关的常量,字段名,字段常量等等。

DatabaseHelper:

LaucherProvider的内部类,继承自SQLiteOpenHelper,数据库表的创建就是在它的onCreate方法里完成的。

三、细说ItemInfo

分几类:

  • 小工具:AppWidget
  • 快捷方式:应用图标
  • 文件夹

而ItemInfo就是抽象出来的东西(拥有的共同点),ItemInfo 对于不同的item,有不同的子类:

  • 小工具对应的是LauncherAppWidgetInfo,增加了小工具的信息
  • 快捷方式对应的是ShortcutInfo,增加了启动Activity的Intent信息
  • 文件夹对应的是FolderInfo,增加了文件夹是否打开的标签,文件夹内图标的信息等等

ItemInfo的成员有几个值得说说:

  • container:表明图标是放在哪里的,是放在Workspace还是Hotseat,还是文件夹里面的。如果是放在Workspace上的,那么值是LauncherSettings.Favorites.CONTAINER_DESKTOP,如果是放在文件夹里面的那么container的值就是文件夹FolderInfo的id。
  • cellX,cellY:表明所在屏幕的哪个位置,cellY表明第几行,cellX表明第几列。如果是小工具占用多行多列的情况,就记录他左上角的位置。
  • spanX,spanY:宽度和高度,快捷方式和文件夹宽高都是1,小工具的宽高就要看具体情况了。
  • title:标题,显示应用的名字,文件夹的名字,小工具的话就不需要这个属性了。
  • itemType: 数据库里保存的表明这个ItemInfo具体是哪种类型的ItemInfo,启动的时候好生成具体的ItemInfo子类对象。

四、Launcher3启动流程

LauncherAppState.java

private LauncherAppState(Context context) {mInvariantDeviceProfile = new InvariantDeviceProfile(mContext);//设备的配置信息mIconCache = new IconCache(mContext, mInvariantDeviceProfile);mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext)); //重点//应用变化的回调,由LauncherModel实现接口,及时的响应数据变化LauncherAppsCompat.getInstance(mContext).addOnAppsChangedCallback(mModel);// Register 应用变化的广播IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);}

Launcher.java

onCreate方法做一些准备工作

protected void onCreate(Bundle savedInstanceState) {LauncherAppState app = LauncherAppState.getInstance(this);mModel = app.setLauncher(this); //需要重点关注initDeviceProfile(app.getInvariantDeviceProfile());//第一次启动后的引导界面,通过sharedprefernce,keyvalue形式存储到xml文件中,初始化一些对象mSharedPrefs = Utilities.getPrefs(this); mIconCache = app.getIconCache();mDragController = new DragController(this);mAllAppsController = new AllAppsTransitionController(this);mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);mAppWidgetHost = new LauncherAppWidgetHost(this);mAppWidgetHost.startListening();mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null);//findviewbyid,通过setupViews()方法把view对象和之前初始化的DragController等东西结合起来setupViews();//重点关注mModel.startLoaderif (!mModel.startLoader(currentScreen)) {if (!internalStateHandled) {// If we are not binding synchronously, show a fade in animation when the first page bind completes.mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0);}} else {// Pages bound synchronously.mWorkspace.setCurrentPage(currentScreen);setWorkspaceLoading(true);}setContentView(mLauncherView);//设置布局}

LauncherModel.java

   public boolean startLoader(int synchronousBindPage) {// Enable queue before starting loader. It will get disabled in Launcher#finishBindingItemsInstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING);synchronized (mLock) {// Don't bother to start the thread if we know it's not going to do anythingif (mCallbacks != null && mCallbacks.get() != null) {final Callbacks oldCallbacks = mCallbacks.get();// Clear any pending bind-runnables from the synchronized load process.mUiExecutor.execute(oldCallbacks::clearPendingBinds);// If there is already one running, tell it to stop.stopLoader();LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel,mBgAllAppsList, synchronousBindPage, mCallbacks);if (mModelLoaded && !mIsLoaderTaskRunning) {// Divide the set of loaded items into those that we are binding synchronously,// and everything else that is to be bound normally (asynchronously).loaderResults.bindWorkspace();// For now, continue posting the binding of AllApps as there are other// issues that arise from that.loaderResults.bindAllApps();loaderResults.bindDeepShortcuts();loaderResults.bindWidgets();return true;} else {startLoaderForResults(loaderResults);}}}return false;}
   public void startLoaderForResults(LoaderResults results) {synchronized (mLock) {stopLoader();mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results);//把LoaderTask对象放到了工作线程中,耗时操作runOnWorkerThread(mLoaderTask);}}

sWorker是一个Handler,可以传递一个Runnable对象,并在相关联的线程中执行。sWorker对应的线程是sWorkerThread,sWorkerThread在LauncherModel类加载的时候就已经开始运行了。

private static void runOnWorkerThread(Runnable r) {if (sWorkerThread.getThreadId() == Process.myTid()) {r.run();} else {// If we are not on the worker thread, then post to the worker handlersWorker.post(r);}}

LoadTask.java

public void run() {//step 1.1: loading workspace 数据层,从数据库中读取所有iteminfo生成对象loadWorkspace();   //step 1.2: bind workspace workspace UI层,加载图标等显示到cellLayout上mResults.bindWorkspace();// step 1.3: send first screen broadcastsendFirstScreenActiveInstallsBroadcast();loadAllApps();updateIconCache();loadDeepShortcuts();}

loadWorkspace():代码很多,做的事就是遍历数据库里的记录,判断类型,生成对应的itemInfo对象(ShortcutInfo,FolderInfo,LauncherAppWidgetInfo)

LoaderResults.java

  public void bindWorkspace() {//重要接口,Launcher.java实现了这个接口,用于更新UICallbacks callbacks = mCallbacks.get(); // Load items on the current page.bindWorkspaceItems(currentWorkspaceItems, currentAppWidgets, mainExecutor);// Load items on other page.bindWorkspaceItems(otherWorkspaceItems, otherAppWidgets, deferredExecutor);}
//加载图标,小工具,文件夹private void bindWorkspaceItems(final ArrayList<ItemInfo> workspaceItems,final ArrayList<LauncherAppWidgetInfo> appWidgets,final Executor executor) {// Bind the workspace itemsint N = workspaceItems.size();for (int i = 0; i < N; i += ITEMS_CHUNK) {final Runnable r = new Runnable() {@Overridepublic void run() {Callbacks callbacks = mCallbacks.get();if (callbacks != null) {//在ui线程callbacks.bindItems(workspaceItems.subList(start, start+chunkSize), false);}}};executor.execute(r);}// Bind the widgets, one at a timeN = appWidgets.size();//....类似Bind the workspace}

Launcher.java

  /*** Bind the items start-end from the list.* Implementation of the method from LauncherModel.Callbacks.*/@Overridepublic void bindItems(final List<ItemInfo> items, final boolean forceAnimateIcons) {Workspace workspace = mWorkspace;long newItemsScreenId = -1;int end = items.size();for (int i = 0; i < end; i++) {final ItemInfo item = items.get(i);final View view;switch (item.itemType) {case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: {ShortcutInfo info = (ShortcutInfo) item;view = createShortcut(info);  //产生Viewbreak;}case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: {view = FolderIcon.fromXml(R.layout.folder_icon, this,(ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),(FolderInfo) item);break;}case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: {view = inflateAppWidget((LauncherAppWidgetInfo) item);if (view == null) {continue;}break;}default:throw new RuntimeException("Invalid Item Type");}workspace.addInScreenFromBind(view, item); //产生view后显示在ui上}workspace.requestLayout();}

加载图标调用了Callback.bindItems方法
文件夹加载调用了Callback.bindFolders
小工具的加载调用了Callback.bindAppWidgets。

Launcher.java

    // Creates a view ,return A View inflated from layoutResId.public View createShortcut(ViewGroup parent, ShortcutInfo info) {BubbleTextView favorite = (BubbleTextView) LayoutInflater.from(parent.getContext()).inflate(R.layout.app_icon, parent, false);favorite.applyFromShortcutInfo(info);  //设置图片和标题favorite.setOnClickListener(ItemClickHandler.INSTANCE);favorite.setOnFocusChangeListener(mFocusHandler);return favorite;}

WorkSpace.java

    public void addInScreenFromBind(View child, ItemInfo info) {int x = info.cellX;int y = info.cellY;if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {int screenId = (int) info.screenId;x = mLauncher.getHotseat().getCellXFromOrder(screenId);y = mLauncher.getHotseat().getCellYFromOrder(screenId);}//其实就是addViewToCellLayout,加到了CellLayout中,与布局图对应起来了addInScreen(child, info.container, info.screenId, x, y, info.spanX, info.spanY);}
  private void addInScreen(View child, long container, long screenId, int x, int y,int spanX, int spanY) {  final CellLayout layout;if (!layout.addViewToCellLayout(child, -1, childId, lp, markCellsAsOccupied)) {// TODO: This branch occurs when the workspace is adding views// outside of the defined grid// maybe we should be deleting these items from the LauncherModel?Log.e(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");}//给view添加长按监听child.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE);}

参考文章:
https://fookwood.com/launcher-start-process-1
https://fookwood.com/launcher-start-process-2


http://chatgpt.dhexx.cn/article/ZwWNAjVD.shtml

相关文章

Launcher3--初识Launcher3

一、Launcher简介 Launcher时开机完成后第一个启动的应用&#xff0c;用来展示应用列表和快捷方式、小部件等。Launcher作为第一个(开机后第一个启动的应用)展示给用户的应用程序&#xff0c;其设计的好坏影响到用户的体验&#xff0c;甚至影响用户购机的判断。所以很多品牌厂商…

Android Launcher3分析及定制主题实现

一. Launcher3 简介 **launcher3是在Launcher2的基础上进化的版本,从Android 4.4 开始就使用Launcher3 .(kk版,kk2版)作为桌面使用,以前我们都在使用Launcher2,我们使用的是KK版本,具体区别后面再说. ** 1 Launcher3 桌面变成了动态管理,launcher2 里面默认最多加载五个worksp…

Android Launcher3简介

一.Launcher3概述 Launcher顾名思义&#xff0c;就是桌面的意思&#xff0c;也是android系统启动后第一个启动的应用程序&#xff0c;这里以android11为例&#xff0c;和其他应用并无区别&#xff0c;只是增加了对其他app和widget的管理窗口&#xff0c;且可以为用户定制化一些…

详细理解准确率、精准率、召回率,F1值等评价指标的含义

转载文章 原博客地址&#xff1a;详解准确率、精确率、召回率、F1值等评价指标的含义 机器学习问题之中&#xff0c;通常需要建立模型来解决具体问题&#xff0c;但对于模型的好坏&#xff0c;也就是模型的泛化能力&#xff0c;如何进行评估&#xff1f;我们可以定一些评价指标…

详解准确率、精确率、召回率、F1值等评价指标的含义

机器学习问题之中&#xff0c;通常需要建立模型来解决具体问题&#xff0c;但对于模型的好坏&#xff0c;也就是模型的泛化能力&#xff0c;如何进行评估呢&#xff1f; 很简单&#xff0c;我们可以定一些评价指标&#xff0c;来度量模型的优劣。比如准确率、精确率、召回率、…

分类性能评价指标——精确率,召回率,F1值详细解释

分类性能的评价指标 准确率 准确率是全部参与分类的文本中&#xff0c;与人工分类结果吻合的文本所占的比例。 即&#xff1a;预测与真实标签相同的比例 A c c u r a c y T P T N T P T N F P F N Accuracy\frac{TPTN}{TPTNFPFN} AccuracyTPTNFPFNTPTN​ 精确率 也称…

准确率、精确率、召回率、F1值

1.TP、TN、FP、FN 先粘一个官方形式的。 用新冠来举例理解。下方正方形为样本&#xff0c;其中 圆的部分认定为检测后是阳性的&#xff0c;其余部分为检测为阴性的&#xff08;但是现在的情况是检测并不完全准确&#xff0c;有可能检测时阴性&#xff0c;但实际上已经有新冠…

机器学习中的二分类问题评价指标之精确率、召回率、F1值通俗理解

引言&#xff1a;对于分类问题&#xff0c;我们在评估一个模型的好坏时&#xff0c;通常想到的是把该模型在测试集上分类结果正确的样本数量比上测试集的样本数量的比值结果&#xff0c;即准确率&#xff08;精确率&#xff09;作为评价准则。但除此之外&#xff0c;还有精确率…

【转】一些因素对F1值的影响

截自&#xff1a;https://blog.csdn.net/qq_27590277/article/details/88374695 https://blog.csdn.net/qq_27590277/article/details/88367082 一些因素对F1值的影响 如果还没了解F1值的话&#xff0c;这里有我之前写的通俗易懂的文章 详谈P(查准率)&#xff0c;R(查全率)&…

keras计算precision、recall、F1值

近期写课程作业&#xff0c;需要用Keras搭建网络层&#xff0c;跑实验时需要计算precision&#xff0c;recall和F1值&#xff0c;在前几年&#xff0c;Keras没有更新时&#xff0c;我用的代码是直接取训练期间的预测标签&#xff0c;然后和真实标签之间计算求解&#xff0c;代码…

F1值(F-Measure)、准确率(Precision)、召回率(Recall) 菜鸡版理解

前置知识&#xff1a; T&#xff08;True&#xff09;&#xff1a; 正确的 F (False) &#xff1a; 错误的 P (Positive) : 正向的/积极的 N (Negetive): 负向的/消极的 则&#xff1a; TP&#xff1a;正确的 预测了 正向的 FN&#xff1a;错误的 预测了 负向的 FP&#xff1a…

准确率、精确率、召回率、F1值学习笔记

一、TN、TP、TN、FP、FN概念 TP与TN都是分对了情况&#xff0c;TP是正类&#xff0c;TN是负类。则推断出&#xff0c;FP是错误的正类&#xff0c;FN是错误的负类。 举例&#xff1a;我们需要从一个班级中的人中寻找所有女生,如果把这个任务当成一个分类器的话,那么女生就是我们…

为何选用F1值(调和平均数)衡量P与R?

二分类问题的性能度量为何选用 F 1 F_1 F1​ 值&#xff1f; 已知混淆矩阵 prediction positiveprediction negativeactuality positiveTrue Positive(TP)False Negative(FN)actuality negativeFalse Positive(FP)True Negative(TN) 其中&#xff1a;Precise&#xff08;精…

精确度/召回率/F1值/Micro-F1和Macro-F1的理解

如下图所示&#xff0c;假设有若干张图片&#xff0c;其中12张是狗的图片其余是猫的图片&#xff0e;现在利用程序去识别狗的图片&#xff0c;结果在识别出的8张图片中有5张是狗的图片&#xff0c;3张是猫的图片&#xff08;属于误报&#xff09;&#xff0e; 图中&#xff0c;…

混淆矩阵、精确率、召回率、F1值、ROC曲线、AUC曲线

假设一个分类器A&#xff0c;分类器A的作用是告诉你一张图片是不是汉堡&#xff0c;我们如果想知道这个分类器的效果到底好不好&#xff0c;如何做&#xff1f; 最简单的方法就是将手机里所有的图片都扔给分类器A看&#xff0c;让分类器告诉我们哪些是汉堡 我们无法直观的看到…

python实现计算精度、召回率和F1值

python实现计算精度、召回率和F1值 摘要&#xff1a;在深度学习的分类任务中&#xff0c;对模型的评估或测试时需要计算其在验证集或测试集上的预测精度&#xff08;prediction/accuracy&#xff09;、召回率&#xff08;recall&#xff09;和F1值。本文首先简要介绍如何计算精…

模型评价指标—F1值

最近空余时间在参加数字中国创新大赛&#xff0c;比赛规则是根据模型的F1值对参赛者进行排名。为了更深刻地理解这个指标&#xff0c;我最近对它做了一些梳理&#xff0c;现在把它分享给更多有需要的人图片。最近在参赛时也发现了一个问题&#xff0c;就是算法在训练集上完全拟…

精确率、召回率、F1 值、ROC、AUC等分类模型评价指标含义与作用详解

文章目录 摘要一、精确率、召回率、F函数、准确率和错误率1、定义2、区别与应用 二、ROC曲线、P-R曲线、AUC1、P-R曲线2、ROC曲线3、AUC 摘要 在涉及机器学习领域的分类问题时&#xff08;尤其是衡量推荐系统性能时&#xff09;&#xff0c;经常会遇到诸如准确率、召回率、ROC…

机器学习F1值的概念

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、什么是F1-score二、计算过程1.首先定义以下几个概念&#xff1a;2.通过第一步的统计值计算每个类别下的precision和recall3. 通过第二步计算结果计算每个类别下…

【数学建模】分类问题的几种常见指标(一)——准确率、召回率、F1值

分类问题的几种常见指标&#xff08;一&#xff09;——错误率、精度、准确率、召回率、F1值 前言1 错误率与精度2 准确率与召回率2.1 混淆矩阵2.2 准确率&#xff08;Precision&#xff09;2.3 召回率&#xff08;Recall&#xff09; 3 F1值&#xff08;F1-score&#xff09;4…