3

我开发了一个 appwidget,它是一个集合小部件,并使用 Loader 从数据库中检索数据,当用户单击列表项时,该项目的详细信息将按意图保存到包中,主要活动将与显示给用户的捆绑信息一起启动。

我的代码按预期工作;但是,我担心小部件如何实际工作、初始化和更新可能出现的边缘情况,这是我没有想到的。在认为我的代码现在可以正常工作大约 5 天后,我发现了一个极端情况。再说一次,我是小部件开发的新手,小部件的 API 花了我很多时间来解决我的问题。

问题

我的 appwidget 的一切似乎在我的手机上都能正常工作,但在我的平板电脑上,在打开应用程序并将新的小部件添加到主屏幕后,它可以正常工作。如果我不先打开应用程序,则我的小部件中不会显示任何内容。

此外,如果我的平板电脑重新启动或关机,那么我当前的小部件将不会显示任何内容。即使在打开我的应用程序之后,我也特别需要为我的其他小部件添加一个新的小部件才能更新。

对于我的手机,除非我添加另一个小部件,否则我很少会遇到小部件上不显示任何内容的问题。至少我不能复制任何东西并保证它不会像在平板电脑上那样工作。

那么,这怎么能在我的手机上几乎完全正常工作,但在我的平板电脑上却一直有问题呢?有没有办法确保我的数据可用,无论我是否在应用程序上打开,以及我是否重新启动我的设备?

代码

GitHub 链接。直接链接到实现 appwidget(java 和 res 文件夹以及清单文件)的 Hub Flavor

应用小部件提供程序

public class ResumeHubWidgetProvider extends AppWidgetProvider {

    private static final String LAUNCH_RESUME_ACTION = "io.github.ciscorucinski.personal.intro.hub.LAUNCH_RESUME_ACTION";

    private static Intent createIntent(Context context) {
        return new Intent(context, ResumeHubWidgetProvider.class);
    }

    private static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                        int appWidgetId) {

        Intent serviceIntent = MyWidgetService.createIntent(context);
        serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));

        // Construct the RemoteViews object
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.resume_hub_list_widget);
        views.setRemoteAdapter(R.id.widget_list, serviceIntent);

        Intent widgetProviderIntent = ResumeHubWidgetProvider.createIntent(context);
        widgetProviderIntent.setAction(ResumeHubWidgetProvider.LAUNCH_RESUME_ACTION);
        widgetProviderIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));

        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, widgetProviderIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        views.setPendingIntentTemplate(R.id.widget_list, pendingIntent);

        // Instruct the widget manager to update the widget
        appWidgetManager.updateAppWidget(appWidgetId, views);

    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {

        // There may be multiple similar widgets active, so update all of them
        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }

    }

    @Override
    public void onReceive(Context context, Intent intent) {

        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

        if (intent.getAction().equals(LAUNCH_RESUME_ACTION)) {

            Timber.i("Intent Action is LAUNCH_RESUME_ACTION");

            // Open the Resume activity with the user selected resume info
            Bundle bundle = intent.getBundleExtra(CREATE_INTENT_BUNDLE);
            context.startActivity(ResumeActivity
                    .createIntentWithFlags(context, bundle,
                            Intent.FLAG_ACTIVITY_NEW_TASK));
        }

        int appWidgetIds[] = appWidgetManager.getAppWidgetIds(new ComponentName(context, ResumeHubWidgetProvider.class));
        appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_list);

        super.onReceive(context, intent);

    }
}

适配器

class HubWidgetAdapter implements RemoteViewsService.RemoteViewsFactory,
        Loader.OnLoadCompleteListener<List<Resume.People>> {

    private Context context;
    private List<Resume.People> data;
    private int appWidgetId;
    private PeopleLoader loader;

    HubWidgetAdapter(Context context, Intent intent) {
        this.context = context;
        appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
    }

    @Override
    public RemoteViews getViewAt(int position) {

        RemoteViews view = new RemoteViews(context.getPackageName(),
                android.R.layout.simple_list_item_1);

        Resume.People person = data.get(position);

        view.setTextViewText(android.R.id.text1, person.seeking_position());
        view.setTextColor(android.R.id.text1, Color.BLACK);

        Bundle bundle = new Bundle();

        bundle.putLong(ResumeActivity.ID, person._id());
        bundle.putString(ResumeActivity.NAME, person.name());
        bundle.putString(ResumeActivity.EMAIL, person.email());
        bundle.putString(ResumeActivity.PHONE, person.phone());
        bundle.putString(ResumeActivity.GITHUB, person.github());
        bundle.putString(ResumeActivity.LINKEDIN, person.linkedin());
        bundle.putString(ResumeActivity.SEEKING, person.seeking_position());

        Intent intent = new Intent();
        intent.putExtra(CREATE_INTENT_BUNDLE, bundle);

        Timber.i("Bundled Person%s", intent);
        view.setOnClickFillInIntent(android.R.id.text1, intent);

        return view;

    }

    @Override
    public void onLoadComplete(Loader<List<Resume.People>> loader, List<Resume.People> data) {
        this.data = data;
    }

    @Override
    public void onCreate() {
        data = new ArrayList<>();
    }

    @Override
    public void onDestroy() {

        if (loader != null) {

            loader.unregisterListener(this);
            loader.cancelLoad();
            loader.stopLoading();
            loader = null;

        }

        data = null;

    }

    @Override public void onDataSetChanged() {

        loader = new PeopleLoader(context);
        loader.registerListener(0, this);
        loader.startLoading();

    }

    @Override public int getCount() { return data.size(); }
    @Override public RemoteViews getLoadingView() { return null; }
    @Override public int getViewTypeCount() { return 1; }
    @Override public long getItemId(int position) { return position; }
    @Override public boolean hasStableIds() { return true; }

}

服务

public class MyWidgetService extends RemoteViewsService {

    static Intent createIntent(Context context) {
        return new Intent(context, MyWidgetService.class);
    }

    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {
        return new HubWidgetAdapter(this.getApplicationContext(), intent);
    }

}

清单(Hub 风味)

Hub 风格是我的代码中唯一具有 appwidgets 的方面,因此我只在此处包含合并到主 Manifest 文件中的 Hub Manifest 文件。

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <activity
            android:name="io.github.ciscorucinski.personal.intro.ui.ResumeActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar"/>
        <receiver android:name="io.github.ciscorucinski.personal.intro.hub.ResumeHubWidgetProvider">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/resume_hub_list_widget_info" />
        </receiver>
        <service
            android:name="io.github.ciscorucinski.personal.intro.hub.MyWidgetService"
            android:exported="false"
            android:permission="android.permission.BIND_REMOTEVIEWS" />
    </application>
</manifest>
4

0 回答 0