launcher appwidget过程分析

本文深入探讨了Launcher中LauncherModel如何区别加载GoogleSearch和普通AppWidget的过程,包括从onCreate和onResume触发的loadUserItems方法,到最终将WidgetSearch添加至workspace与普通AppWidgets的不同加载机制。

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

 
  1. Launcher是怎样区别加载GoogleSearch和其它普通的AppWidget的呢?
  2. 在Launcher中有一个static成员LauncherModel,它主要负责维护Launcher的状态和提供一些更新Launcher数据库状态的API。LaunchModel中用不同的ArrayList记录ItemInfo和LauncherAppWidgetInfo的信息(ITEM_TYPE_APPLICATION, ITEM_TYPE_USER_FOLDER, ITEM_TYPE_LIVE_FOLDER, ITEM_TYPE_WIDGET_SEARCH这些类型的Item都被记录在ItemInfo类型中)。
  3. 具体的加载过程大概是:在Launcher的onCreate和onResume中都调用了LauncherModel::loadUserItems方法。之后的顺序是LauncherModel::loadUserItems->Launcher::onDesktopItemsLoaded->Launcher::bindDesktopItems->...->最后在Launcher::DesktopBinder::handleMessage中通过Launcher::bindItems方法加载了Widget Search到workspace(控制桌面显示区域的class)上,而通过Launcher::bindAppWidgets加载了普通的AppWidgets。
  4. 看一下Widget添加的过程吧。Launcher通过addSearch直接用inflate的方法产生一个GoogleSearchWidget的View,并添加到workspace;而普通的AppWidget则是通过completeAddAppWidget中产生并添加一个AppWidgetHostView来实现的。
### 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、付费专栏及课程。

余额充值