6

我有一个 AppWidget,其中包含一个 StackView。除了 AppWidget,我还有一个服务,当用户将我的 AppWidget 添加到他们的主屏幕时,该服务会启动,每两个小时轮询一次新数据。当服务找到新数据时,我需要它提醒我的 AppWidget,并将该数据传递给 RemoteViewsService(它有我的 RemoteViewsFactory),以便它可以为新数据创建必要的视图。

目前,当服务找到新数据时,我让它向我的 AppWidget 广播已找到新数据,并将该数据作为意图中的整数数组传递。

我的 AppWidgetProvider 中的 onReceive 方法将数据拉出,然后我完成了设置新意图的过程,该意图传递给 AppWidget 的 RemoteViews。下面的示例代码:

public void onReceive( Context context, Intent intent )
{
    int[] appWidgetIds = appWidgetManager.getAppWidgetIds( new ComponentName( context,  SampleAppWidgetProvider.class ) );

    int[] sampleData = intent.getIntArrayExtra( Intent.EXTRA_TITLE );
    for ( int i = 0; i < appWidgetIds.length; i++ )
    {
        // RemoteViewsFactory service intent
        Intent remoteViewsFactoryIntent = new Intent( context, SampleAppWidgetService.class );
        remoteViewsFactoryIntent.putExtra( AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i] );
        remoteViewsFactoryIntent.setData( Uri.parse( remoteViewsFactoryIntent.toUri( Intent.URI_INTENT_SCHEME ) ) );
        remoteViewsFactoryIntent.putExtra( Intent.EXTRA_TITLE, sampleData );

        RemoteViews rv = new RemoteViews( context.getPackageName(), R.layout.widget_layout );

        // Sync up the remoteviews factory
        rv.setRemoteAdapter( appWidgetIds[i], R.id.sample_widget, remoteViewsFactoryIntent );           
        rv.setEmptyView( R.id.sample_widget, R.id.empty_view );

        appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
    }

    super.onUpdate( context, appWidgetManager, appWidgetIds );
}

这是第一次。数据由 RemoteViewsService/RemoteViewsFactory 显示。随后的新数据不会命中 RemoteViewsFactory 的构造函数,因为该工厂的服务已经在运行。

我该如何更新数据?我觉得我应该使用 onDataSetChanged,但是如何访问我从 AppWidget 的 onReceive 传递的意图?

我将不胜感激有关如何正确处理此问题的任何见解。谢谢。

4

4 回答 4

5

我对传递给 RemoteViewsFactory 的整数数组的解决方案是使用 BroadcastReceiver 解决的。我扩展了我的 RemoteViewsFactory 以实现 BroadcastReceiver(特别是 onReceive),并在工厂的构造函数中将它注册到我的应用程序中(这也意味着我在 onDestroy 中取消了它的注册)。这样,我就能够使用我在 AppWidgetProvider 的 onReceive 中拥有的整数数组来广播意图,并在 RemoteViewsFactory 中接收它。

确保还调用 AppWidgetManager 的 notifyAppWidgetViewDataChanged,以便 RemoteViewsFactory 知道它之前使用的数据已失效,并提供一个新的整数数组以创建新的 RemoteViews。

于 2011-09-13T16:03:09.043 回答
3

为了进一步阐述上述史蒂夫的解决方案,以使 arne.jans 和其他人受益,我通过以下方式实现了 Steven 的解决方案:

  • 将其提取StackRemoteViewsFactory到自己的类文件中
  • 用一个扩展它BroadcastReceiver
  • 实现onReceive()将新数据保存到静态变量的方法,该类在需要数据StackRemoteViewsFactory时也可以访问该静态变量getViewAt
  • 通过传递所有小部件ID,因此我可以在该方法中Intent调用所有小部件。notifyAndUpdateonReceive()
  • 最后,我将接收器的标准定义添加到 AndroidManifest.xml
于 2012-06-16T04:19:26.803 回答
3

我没有使用 BroadcastReceiver 扩展 RemoteViewFactory,而是在其上实现动态 BroadcastReceiver 以将字符串从 AppWidgetProvider 传递给 RemoteViewFactory。

像这样:

public class MyWidgetProvider extends AppWidgetProvider {
    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);

        String action = intent.getAction();
        if (action.equals("android.appwidget.action.APPWIDGET_UPDATE")) {
            .....
        } else if (action.equals("some.string.you.want.ACTION_TODO")) {
            String url = intent.getStringExtra("some.string.you.want.EXTRA_URL");

            // Send broadcast intent to pass mUrl variable to the MyContentFactory.
            Intent broadcastIntent = new Intent("some.string.you.want.ACTION_UPDATE_URL");
            broadcastIntent.putExtra("some.string.you.want.EXTRA_URL", url);
            context.sendBroadcast(broadcastIntent);
        }
        .....
    }
}

public class MyContentFactory implements RemoteViewsService.RemoteViewsFactory {
    private Context mContext;
    private String mUrl; // target to update
    private BroadcastReceiver mIntentListener;

    public MyContentFactory(Context context, Intent intent) {
        mContext = context;
        setupIntentListener();
    }

    @Override
    public void onDestroy() {
        teardownIntentListener();
    }

    private void setupIntentListener() {
        if (mIntentListener == null) {
            mIntentListener = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    // Update mUrl through BroadCast Intent
                    mUrl = intent.getStringExtra("some.string.you.want.EXTRA_URL");
                }
            };
            IntentFilter filter = new IntentFilter();
            filter.addAction("some.string.you.want.ACTION_UPDATE_URL");
            mContext.registerReceiver(mIntentListener, filter);
        }
    }

    private void teardownIntentListener() {
        if (mIntentListener != null) {
            mContext.unregisterReceiver(mIntentListener);
            mIntentListener = null;
        }
    }
}
于 2013-04-18T07:35:45.673 回答
1

另一种选择是使用文件系统或 sqlite 数据库,例如

在 AppWidgetProvider 中:

 File file = new File(context.getCacheDir(), "filename that service also knows");
 writeFile(file, "my content");  // impl. not shown; uses BufferedWriter.java

在远程视图服务中:

 File file = new File(context.getCacheDir(), "filename that service also knows");
 if (file.exists()) {
     // handle params contained within file
     file.delete(); // clear for next run
 } 
于 2013-12-02T23:09:02.217 回答