前段时间做了个桌面的widget,第一次接触AppWidget,遇到了不少问题,今天整理下和大家探讨下.
至于AppWidget的有些基础知识,我在这里就不多说了,大家有什么不明白,随便百度下,就有很多答案.今天主要说一下我在往桌面上添加时遇到的问题.
如图所示,中间的Recommended就是一个appwidget添加在桌面上.下面我们就来说说添加的流程.
首先,上面的页面不是手机页面,是阅读设备,用的是安卓系统,类似平板一样的设备.桌面也不是安卓原生的Luncher,所以也不可能像手机那样长按空白选择,然后滑动选择位置就添加上去了,而且还要求开机就默认在桌面上,位置也不能变(我们也没做长按可以移动widget的功能).
加载流程如下:
1.获取ID
2.获取appwidget的ComponentName
3.绑定bindAppWidgetId
4.获取AppWidgetHostView(RemoteViews并不是真的view)
5.添加AppWidgetHostView到父Layput中
代码如下:
private void addRecommendationsWidget() {
int APPWIDGET_HOST_ID = 1024;
AppWidgetHost appWidgetHost = new AppWidgetHost(getApplicationContext(), APPWIDGET_HOST_ID);
int appWidgetId = appWidgetHost.allocateAppWidgetId();
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
List<AppWidgetProviderInfo> providers = appWidgetManager.getInstalledProviders();
if (providers == null) {
Log.e(TAG, "failed to find installed widgets ");
return;
}
final int providerCount = providers.size();
AppWidgetProviderInfo appWidgetProviderInfo = null;
for (int i = 0; i < providerCount ; i++) {
ComponentName provider = providers.get(i).provider;
if (provider != null && provider.getPackageName().equals("com.xxxx.android.xxxx")) {
appWidgetProviderInfo = providers.get(i);
break;
}
}
if (appWidgetProviderInfo == null) {
Log.e(TAG, "failed to find recommendations widget ");
return;
}
int sdkVersion = Integer.valueOf(android.os.Build.VERSION.SDK);
if (sdkVersion > 15) {
final String methodName = "bindAppWidgetIdIfAllowed";
boolean success = bindAppWidgetId(appWidgetManager, appWidgetId, appWidgetProviderInfo.provider, methodName);
if (!success) {
addWidgetPermission(appWidgetManager);
boolean bindAllowed = bindAppWidgetId(appWidgetManager, appWidgetId, appWidgetProviderInfo.provider, methodName);
if (!bindAllowed) {
Log.e(TAG, " failed to bind widget id : " + appWidgetId);
return;
}
}
} else {
boolean success = bindAppWidgetId(appWidgetManager, appWidgetId, appWidgetProviderInfo.provider, "bindAppWidgetId");
if (!success) {
Log.e(TAG, " failed to bind widget id : " + appWidgetId);
return;
}
}
Log.d(TAG, " successful to bind widget id : " + appWidgetId);
AppWidgetHostView hostView = appWidgetHost.createView(this, appWidgetId, appWidgetProviderInfo);
appWidgetHost.startListening();
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, appWidgetProviderInfo.minHeight);
RelativeLayout widgetLayout = (RelativeLayout) findViewById(R.id.recommendation_widget_layout);
widgetLayout.addView(hostView, params);
}
private void addWidgetPermission(AppWidgetManager appWidgetManager) {
String methodName = "setBindAppWidgetPermission";
try {
Class [] argsClass = new Class[]{String.class, boolean.class};
Method method = appWidgetManager.getClass().getMethod(methodName, argsClass);
Object [] args = new Object[]{this.getPackageName(), true};
try {
method.invoke(appWidgetManager, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
private boolean bindAppWidgetId(AppWidgetManager appWidgetManager, int appWidgetId, ComponentName componentName, String methodName) {
boolean success = false;
Class [] argsClass = new Class[]{int.class, ComponentName.class};
try {
Method method = appWidgetManager.getClass().getMethod(methodName, argsClass);
Object [] args = new Object[]{appWidgetId, componentName};
try {
method.invoke(appWidgetManager, args);
success = true;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return success;
}
代码比较简单,一看应该就很清除.中间为什么要判断sdk版本呢?因为我发现4.0.4和4.2.2绑定的方法不一样,(我也只验证了这两个版本,其它的你们可以看文档)这里为了兼容,采用反射的方法绑定ID.
4.0.4绑定ID用AppWidgetManager的bindAppWidgetId()函数,而且需要添加权限:
<uses-permission android:name="android.permission.BIND_APPWIDGET"/>.
4.2.2绑定ID用AppWidgetManager的bindAppWidgetIdIfAllowed()函数,同时会返回绑定结果的boolean值,而且需要添加权限:
<uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
权限一定不要忘记,setBindAppWidgetPermission(true)这个函数是用来给添加到桌面上授权,可以避免添加时弹出需要授权的对话框(安卓系统的授权对话框).由于这个是hide API,所以也用反射的方式调用.
最后一点切记,必须有System权限的app才能用这种方法,也就是安装在system/app下面的应用才可以.
大家有什么不同的看法可以一起讨论!共同进步!下一篇我会讲一下appwidget滑动翻页的问题!第一次写博客,不足之处,请大家多多指正.