尝试在 Android 12 上托管一些小部件(在本例中为 Gmail 小部件)时出现错误。我还有几个显示类似错误的小部件。
乍一看,问题似乎出在小部件的 xml 文件中,但在以前的 Android 版本上一切正常。Android 12 主页启动器也会按预期加载小部件。
Android 12 上的小部件托管是否已更改?小部件制作有变化,但我没有发现托管有任何变化。
错误:
com.test.widgethosttest W/AppWidgetHostView: Error inflating RemoteViews
android.view.InflateException: Binary XML file line #19 in com.google.android.gm:layout/widget: Can't convert value at index 7 to dimension: type=0x1
Caused by: java.lang.UnsupportedOperationException: Can't convert value at index 7 to dimension: type=0x1
at android.content.res.TypedArray.getDimensionPixelSize(TypedArray.java:788)
at android.view.ViewGroup$MarginLayoutParams.<init>(ViewGroup.java:8465)
at android.widget.FrameLayout$LayoutParams.<init>(FrameLayout.java:452)
at android.appwidget.AppWidgetHostView.generateLayoutParams(AppWidgetHostView.java:463)
at android.appwidget.AppWidgetHostView.generateLayoutParams(AppWidgetHostView.java:68)
at android.view.LayoutInflater.inflate(LayoutInflater.java:673)
at android.view.LayoutInflater.inflate(LayoutInflater.java:538)
at android.widget.RemoteViews.inflateView(RemoteViews.java:5484)
at android.widget.RemoteViews.apply(RemoteViews.java:5453)
at android.appwidget.AppWidgetHostView.applyRemoteViews(AppWidgetHostView.java:572)
at android.appwidget.AppWidgetHostView.updateAppWidget(AppWidgetHostView.java:507)
at android.appwidget.AppWidgetHost.updateAppWidgetView(AppWidgetHost.java:485)
at android.appwidget.AppWidgetHost$UpdateHandler.handleMessage(AppWidgetHost.java:147)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7842)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
活动代码,在 github 上找到。它非常标准,并且在以前的 Android 版本上运行良好:
public class MainActivity extends AppCompatActivity {
AppWidgetManager mAppWidgetManager;
AppWidgetHost mAppWidgetHost;
ViewGroup mainlayout;
private static final int APPWIDGET_HOST_ID = 0x9345;
private static final int REQUEST_CREATE_APPWIDGET = 0x9344;
private static final int REQUEST_PICK_APPWIDGET = 0x9343;
/**
* Called on the creation of the activity.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainlayout = (ViewGroup) findViewById(R.id.main_layout);
mAppWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
mAppWidgetHost = new AppWidgetHost(getApplicationContext(), APPWIDGET_HOST_ID);
}
/**
* Launches the menu to select the widget. The selected widget will be on
* the result of the activity.
*/
void selectWidget() {
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
addEmptyData(pickIntent);
startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);
}
/**
* This avoids a bug in the com.android.settings.AppWidgetPickActivity,
* which is used to select widgets. This just adds empty extras to the
* intent, avoiding the bug.
*
* See more: http://code.google.com/p/android/issues/detail?id=4272
*/
void addEmptyData(Intent pickIntent) {
ArrayList<AppWidgetProviderInfo> customInfo = new ArrayList<AppWidgetProviderInfo>();
pickIntent.putParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_INFO, customInfo);
ArrayList<Bundle> customExtras = new ArrayList<Bundle>();
pickIntent.putParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_EXTRAS, customExtras);
}
/**
* If the user has selected an widget, the result will be in the 'data' when
* this function is called.
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == REQUEST_PICK_APPWIDGET) {
configureWidget(data);
} else if (requestCode == REQUEST_CREATE_APPWIDGET) {
createWidget(data);
}
} else if (resultCode == RESULT_CANCELED && data != null) {
int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
if (appWidgetId != -1) {
mAppWidgetHost.deleteAppWidgetId(appWidgetId);
}
}
}
/**
* Checks if the widget needs any configuration. If it needs, launches the
* configuration activity.
*/
private void configureWidget(Intent data) {
Bundle extras = data.getExtras();
int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
if (appWidgetInfo.configure != null) {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
intent.setComponent(appWidgetInfo.configure);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
startActivityForResult(intent, REQUEST_CREATE_APPWIDGET);
} else {
createWidget(data);
}
}
/**
* Creates the widget and adds to our view layout.
*/
public void createWidget(Intent data) {
Bundle extras = data.getExtras();
int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
AppWidgetHostView hostView = mAppWidgetHost.createView(getApplicationContext(), appWidgetId, appWidgetInfo);
hostView.setAppWidget(appWidgetId, appWidgetInfo);
mainlayout.addView(hostView);
Log.i("MainActivity", "The widget size is: " + appWidgetInfo.minWidth + "*" + appWidgetInfo.minHeight);
}
/**
* Registers the AppWidgetHost to listen for updates to any widgets this app
* has.
*/
@Override
protected void onStart() {
super.onStart();
mAppWidgetHost.startListening();
}
/**
* Stop listen for updates for our widgets (saving battery).
*/
@Override
protected void onStop() {
super.onStop();
mAppWidgetHost.stopListening();
}
/**
* Removes the widget displayed by this AppWidgetHostView.
*/
public void removeWidget(AppWidgetHostView hostView) {
mAppWidgetHost.deleteAppWidgetId(hostView.getAppWidgetId());
mainlayout.removeView(hostView);
}
/**
* Handles the menu.
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Log.i("MainActivity", "Menu selected: " + item.getTitle() + " / " + item.getItemId() + " / " + R.id.addWidget);
switch (item.getItemId()) {
case R.id.addWidget:
selectWidget();
return true;
case R.id.removeWidget:
removeWidgetMenuSelected();
return false;
}
return super.onOptionsItemSelected(item);
}
/**
* Handle the 'Remove Widget' menu.
*/
public void removeWidgetMenuSelected() {
int childCount = mainlayout.getChildCount();
if (childCount > 1) {
View view = mainlayout.getChildAt(childCount - 1);
if (view instanceof AppWidgetHostView) {
removeWidget((AppWidgetHostView) view);
Toast.makeText(getApplicationContext(), R.string.widget_removed_popup, Toast.LENGTH_SHORT).show();
return;
}
}
Toast.makeText(getApplicationContext(), R.string.no_widgets_popup, Toast.LENGTH_SHORT).show();
}
/**
* Creates the menu with options to add and remove widgets.
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.widget_menu, menu);
return true;
}
}