AppWidget之AppWidgetService

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桌面添加AppWidget时需要调用:

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;
    }
}











你可能感兴趣的:(Android)