【问题标题】:"Error inflating RemoteViews" when hosting some widgets on Android 12在 Android 12 上托管某些小部件时出现“错误膨胀 RemoteViews”
【发布时间】:2021-11-11 10:37:19
【问题描述】:

尝试在 Android 12 上托管 一些小部件(在本例中为 Gmail 小部件)时出现错误。我还有几个小部件显示类似错误。

乍一看,问题似乎出在小部件的 xml 文件中,但在以前的 Android 版本上一切正常。 Android 12 主页启动器也会按预期加载小部件。

Android 12 上的小部件托管是否发生了变化? widgets making有变化,但我没有发现托管有任何变化。

错误:

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

【问题讨论】:

标签: android-widget android-12


【解决方案1】:

原来这是 Android 12 的错误。 它已在 Android 12L 中修复。

https://issuetracker.google.com/issues/205749786

【讨论】:

  • 我在将一些小部件添加到我正在开发的自定义启动器中时遇到问题:一些小部件的大小不正确。例如,数字时钟小部件的尺寸不正确(模拟时钟和大多数其他小部件工作正常)。我尝试了您的代码,看看它是否解决了问题。它没。您可以使用此代码添加数字时钟小部件吗?
  • 我找到了问题的原因:我没有打电话给AppWidgetHostView.updateAppWidgetSize(...)。看来至少某些小部件需要此方法调用。
  • @dazed,这段代码来自Github,不完整。如果您正在制作启动器,您可能应该使用最新的 Google Launcher3 中的代码。
猜你喜欢
  • 1970-01-01
  • 2012-11-21
  • 2021-12-28
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-07
相关资源
最近更新 更多