AppCompat打破了Launcher Widget的能力."找不到任何视图,使用错误视图"

Mic*_*ern 4 android launcher

我是一名发射器开发人员,小部件的基础始终遵循我发现的这个简单指南:托管Android小部件.现在,使用演示应用程序时此方法可以100%运行.问题是,一旦我添加AppCompat主题并扩展AppCompatActivity而不是Activity 最新com.android.support:appcompat-v7:25.1.1,我遇到了问题.从ACTION_APPWIDGET_PICK对话框中选择某些小部件后,我得到如下错误:

W/AppWidgetHostView: updateAppWidget couldn't find any view, using error view android.widget.RemoteViews$ActionException: view: android.support.v7.widget.AppCompatImageView can't use method with RemoteViews: setImageResource(int)
at android.widget.RemoteViews.getMethod(RemoteViews.java:775)
at android.widget.RemoteViews.access$300(RemoteViews.java:69)
at android.widget.RemoteViews$ReflectionAction.apply(RemoteViews.java:1266)
at android.widget.RemoteViews.performApply(RemoteViews.java:2587)
at android.widget.RemoteViews.apply(RemoteViews.java:2547)
at android.appwidget.AppWidgetHostView.updateAppWidget(AppWidgetHostView.java:395)
at android.appwidget.AppWidgetHost.createView(AppWidgetHost.java:336)
at com.lgfischer.widgethost.WidgetHostExampleActivity.createWidget(WidgetHostExampleActivity.java:129)
at com.lgfischer.widgethost.WidgetHostExampleActivity.onActivityResult(WidgetHostExampleActivity.java:93)
at android.app.Activity.dispatchActivityResult(Activity.java:6168)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3732)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3779)
at android.app.ActivityThread.access$1300(ActivityThread.java:162)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1461)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:189)
at android.app.ActivityThread.main(ActivityThread.java:5529)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:950)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:745)
Run Code Online (Sandbox Code Playgroud)

另外还有AppWidgetHostView显示器"Couldn't add widget".基于错误日志,人们自然会看一下WidgetHostExampleActivity.java line #129,但这只是调用mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);.

似乎代码可以工作appcompat-v7:22.1.1,但没有上面的代码.

注意:

  1. 我已经测试并确认此错误Android 5.0.2Android 7.1.1
  2. 这只发生在一些小部件上.一些失败的是Default Calendar appon Android 7.1.1and Play - My Libraryplay store小部件.
  3. 在Play商店的实际启动器中,我创建了一个自定义小部件选择活动,但仍然存在所描述的问题

我有这个项目的完整源代码,我在上面提到了修改:Google Drive

这是完整的WidgetHostExampleActivity:

public class WidgetHostExampleActivity extends AppCompatActivity{


    final static int APPWIDGET_HOST_ID = 111;
    final static int REQUEST_PICK_APPWIDGET = 222;
    final static int REQUEST_CREATE_APPWIDGET = 333;

    static final String TAG = "WidgetHostExampleActivity";

    AppWidgetManager mAppWidgetManager;
    AppWidgetHost mAppWidgetHost;

    ViewGroup mainlayout;

    /**
     * Called on the creation of the activity.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mainlayout = (ViewGroup) findViewById(R.id.main_layout);

        mAppWidgetManager = AppWidgetManager.getInstance(this);
        mAppWidgetHost = new AppWidgetHost(this, 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 = this.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) {
        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(this, appWidgetId, appWidgetInfo);
        hostView.setAppWidget(appWidgetId, appWidgetInfo);
        mainlayout.addView(hostView);

        Log.i(TAG, "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(TAG, "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(this, R.string.widget_removed_popup, Toast.LENGTH_SHORT).show();
                return;
            }
        }
        Toast.makeText(this, 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的settings.gradel:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"

    defaultConfig {
        applicationId "com.lgfischer.widgethost"
        minSdkVersion 11
        targetSdkVersion 22

    }

    buildTypes {
        release {
            minifyEnabled false
            shrinkResources false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}


dependencies {
    compile 'com.android.support:appcompat-v7:25.1.1'
}
Run Code Online (Sandbox Code Playgroud)

PS:我现在几乎没有发布问题,所以当我这样做时,你知道这是一个真正的问题.

das*_*ima 14

将管理器和主机的上下文更改为应用程序上下文而不是活动上下文.

AppWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
mAppWidgetHost = new AppWidgetHost(getApplicationContext(), APPWIDGET_HOST_ID);
Run Code Online (Sandbox Code Playgroud)

刚刚为我解决了这个问题.

  • 编辑:好的,如果你也这样做:"mAppWidgetHost.createView(getApplicationContext(),appWidgetId,appWidgetInfo);" (5认同)