Android Launcher加载widget 等view的流程

本文详细解析了Android 8.0版本中Launcher的应用加载流程,包括主屏幕布局、应用程序图标和小部件的加载过程。文章重点介绍了Launcher如何从后台加载数据、更新应用列表以及加载桌面小部件等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

android版本8.0

1. Launcher加载app,shortcut,widget主流程

LauncherLauncherModelOtherSignalLoaderTaskLoaderResultsBgDataModel.widgetsModelWorkspaceCellLayoutShortcutAndWidgetContaineronCreate()1LauncherAppState.setLauncher2startLoaderFromBackground()3startLoader4startLoaderForResults5loadWorkspace()6bindWorkspace7loadAllApps()8bindAllApps9loadDeepShortcuts()10bindDeepShortcuts11update()12bindWidgets13bindWorkspaceItems14bindItems15addInScreen16addViewToCellLayout17addView(child, index, lp)18LauncherLauncherModelOtherSignalLoaderTaskLoaderResultsBgDataModel.widgetsModelWorkspaceCellLayoutShortcutAndWidgetContainer

2.loadWorkspace

final HashMap<String, Integer> installingPkgs =
    mPackageInstaller.updateAndGetActiveSessionCache();
mBgDataModel.workspaceScreens.addAll(LauncherModel.loadWorkspaceScreensDb(context));

Map<ShortcutKey, ShortcutInfoCompat> shortcutKeyToPinnedShortcuts = new HashMap<>();
final LoaderCursor c = new LoaderCursor(contentResolver.query(
    LauncherSettings.Favorites.CONTENT_URI, null, null, null, null), mApp);
.
.//create info
.
c.checkAndAddItem(info, mBgDataModel);

public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) {
    if (checkItemPlacement(info, dataModel.workspaceScreens)) {
        dataModel.addItem(mContext, info, false);
    } else {
        markDeleted("Item position overlap");
    }
}

3.loadAllApps

final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);

for (int i = 0; i < apps.size(); i++) {
    LauncherActivityInfo app = apps.get(i);
    mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
}


LauncherAppsILauncherAppsLauncherAppsServicePackageManagerInternalPackageManagerServicegetActivityList1getLauncherActivities2getLauncherActivities3queryActivitiesForUser4queryIntentActivities5queryIntentActivitiesInternal6LauncherAppsILauncherAppsLauncherAppsServicePackageManagerInternalPackageManagerService

4. LoadWidgets

mBgDataModel.widgetsModel.update(mApp, null);

Context context = app.getContext();
final ArrayList<WidgetItem> widgetsAndShortcuts = new ArrayList<>();
try {
    PackageManager pm = context.getPackageManager();
    InvariantDeviceProfile idp = app.getInvariantDeviceProfile();

    // Widgets
    AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(context);
    for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(packageUser)) {
        widgetsAndShortcuts.add(new WidgetItem(LauncherAppWidgetProviderInfo
                                               .fromProviderInfo(context, widgetInfo), pm, idp));
    }

    // Shortcuts
    for (ShortcutConfigActivityInfo info : LauncherAppsCompat.getInstance(context)
         .getCustomShortcutActivityList(packageUser)) {
        widgetsAndShortcuts.add(new WidgetItem(info));
    }
    setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser);
} catch (Exception e) {
    if (!FeatureFlags.IS_DOGFOOD_BUILD && Utilities.isBinderSizeError(e)) {
        // the returned value may be incomplete and will not be refreshed until the next
        // time Launcher starts.
        // TODO: after figuring out a repro step, introduce a dirty bit to check when
        // onResume is called to refresh the widget provider list.
    } else {
        throw e;
    }
}

### Launcher3 中 `updateAppWidget` 方法的 AppWidget 加载流程 #### 1. 广播接收器注册 为了使应用微件能够响应更新请求,在清单文件中定义了一个 `<receiver>` 元素来配置广播接收器。此元素需设置 `android:name` 属性指向具体的 `AppWidgetProvider` 实现类[^5]。 ```xml <receiver android:name=".MyAppWidgetProvider"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/my_app_widget_info" /> </receiver> ``` #### 2. 更新事件触发 当用户操作或其他条件满足时,系统会向已注册的应用微件发送 `ACTION_APPWIDGET_UPDATE` 消息。此时,对应的 `BroadcastReceiver` 将接收到意图并调用其内部的方法处理逻辑。 #### 3. 获取待更新的小部件ID列表 在 `onReceive()` 或者专门重写的 `onUpdate()` 函数内,通过传入参数中的 `Intent` 对象获取要刷新的具体小部件 ID 数组: ```java @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // To prevent any ANR timeouts, we perform the update in a service } ``` 这里传递过来的是一个整型数组 `appWidgetIds`,包含了当前需要被更新的所有实例化后的组件编号[^2]。 #### 4. 启动后台服务执行实际工作 考虑到性能因素以及避免主线程阻塞的风险,通常不会直接在此处完成视图构建等工作;而是启动一个新的 IntentService 来异步地进行真正的 UI 绘制和服务端通信等耗时任务[^1]。 ```java // Inside onUpdate method of your widget provider class. for (int appWidgetId : appWidgetIds) { Intent intent = new Intent(context, UpdateService.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); context.startService(intent); } ``` #### 5. 构建远程视图对象 在 Service 类里边,依据不同的需求定制 RemoteViews 实例,它代表了最终呈现在桌面环境下的可视化结构。需要注意的是,由于安全性和效率方面的考量,可供选用的布局容器和控件种类有限[^4]。 ```java RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout); views.setTextViewText(R.id.text_view_id, "Updated Text"); views.setImageViewResource(R.id.image_view_id, R.drawable.new_image); ``` #### 6. 提交更改至管理器 最后一步就是把准备好的 RemoteViews 返回给负责协调各个插件显示状态的对象——即 `AppWidgetManager` 的单例实体。这可以通过调用 `updateAppWidget(int[], RemoteViews)` 完成,从而通知宿主程序重新渲染指定 ID 所关联的那个区域的内容[^3]。 ```java AppWidgetManager manager = AppWidgetManager.getInstance(this); manager.updateAppWidget(appWidgetId, views); ``` 上述过程构成了完整的 `updateAppWidget` 流程描述,涵盖了从初始消息捕获到最后界面呈现的关键环节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值