1. bindAppWidgetId方法
功能:实现绑定appwidgetid与componentname
public void bindAppWidgetId(int appWidgetId, ComponentName provider) { //根据appWidgetId去获得AppWidgetId对象 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); //根据ComponentName去获得Provider对象 Provider p = lookupProviderLocked(provider); //appWidgetId与Provider的相互绑定 id.provider = p; p.instances.add(id); //如果是第一次创建该AppWidget,那么需要发送Enabled广播 int instancesSize = p.instances.size(); if (instancesSize == 1) { sendEnableIntentLocked(p); } //发送Update广播,通知remote端更新,也就是执行我们些的onUpdate方法 sendUpdateIntentLocked(p, new int[] { appWidgetId }); registerForBroadcastsLocked(p, getAppWidgetIds(p)); }
这里要关注的是,此方法一般不直接调用,而是通过AppWidgetManager来间接地调用。AppWidgetManager类中对这个方法进行了封装,AppWidgetService只是实现了这个接口。
IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE); sService = IAppWidgetService.Stub.asInterface(b); public void bindAppWidgetId(int appWidgetId, ComponentName provider) { sService.bindAppWidgetId(appWidgetId, provider); }
什么时候会调用这个方法呢?
在AppWidgetPickActivity.java的onClick方法中会调用这个方法来实现绑定
public void onClick(DialogInterface dialog, int which) { //根据位置来确定用户想要创建哪个AppWidget Intent intent = getIntentForPosition(which); int result; //将从Launcher中获得的mAppWidgetId与用户选择的AppWidget进行绑定 mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent()); result = RESULT_OK; setResultData(result, null); finish(); }
当Launcher.java要在桌面添加一个AppWidget时,它会先申请一个appWidgetId,然后把这个appWidgetId传递给AppWidgetPickActivity.java;用户能够看到可以安装的AppWidget并且选择其中一个,这时就需要调用此函数将AppWidget与用户选择的ComponentName绑定;最关键的是在绑定之后,就需先发送Enabled的广播(如果是第一此添加此AppWidget),然后再发送Update广播。那么在AppWidgetProvider中的相应方法就能够接收到这两个广播,作相应的处理(作何处理由开发AppWidget的开发者决定)。
2.allocateAppWidgetId方法
功能:申请appWidgetId(一般是在Launcher中申请,通过AppWidgetHost来间接调用)
public int allocateAppWidgetId(String packageName, int hostId) { int callingUid = enforceCallingUid(packageName); //申请到的appWidgetId从1开始,依次递增,每次关机后应该会还原回去重新分配 int appWidgetId = mNextAppWidgetId++; //通过local端的packageName和hostId去得到Host对象 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); //创建AppWidgetId实例,并初始化它的appWidgetId和host AppWidgetId id = new AppWidgetId(); id.appWidgetId = appWidgetId; id.host = host; //将host与新创建的AppWidgetId创建联系:appWidgetId host.instances.add(id); //mAppWidgetIds中保存新创建的AppWidgetId,在lookupOrAddHostLocked方法中也将host保存在mHosts中(先在mHosts中查询是否存在,若存在则直接返回,若不存在,则创建新的并保存) mAppWidgetIds.add(id); return appWidgetId; } int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1; (AppWidgetManager.INVALID_APPWIDGET_ID = 0;)
在申请appWidgetId的过程中,还将appWidgetId与Host进行了绑定。这里的appWidgetId只是一个从1开始递增的数,类型为int型。
AppWidgetHost对它进行了封装:
public int allocateAppWidgetId() { if (mPackageName == null) { mPackageName = mContext.getPackageName(); } return sService.allocateAppWidgetId(mPackageName, mHostId); }
Launcher.java public void onClick(DialogInterface dialog, int which) { //用户选择添加一个AppWidget,那么此时就需要申请一个appWidgetId,并且将它作为Intent的参数传递给AppWidgetPickActivity.java case AddAdapter.ITEM_APPWIDGET: { int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId(); Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK); pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET); break; } }