Передача массива целых чисел из AppWidget в существующий RemoteViewsService для визуализации с помощью RemoteViewsFactory - PullRequest
6 голосов
/ 10 сентября 2011

У меня есть AppWidget, в котором есть StackView. Наряду с AppWidget у меня есть служба, которая запускается, когда пользователь добавляет мой AppWidget на свой домашний экран, который каждые два часа опрашивает новые данные. Когда служба находит новые данные, мне нужно для этого предупредить мой AppWidget, а также передать эти данные в RemoteViewsService (который имеет мой RemoteViewsFactory), чтобы он мог создать необходимые представления для новых данных.

В настоящее время, когда служба находит новые данные, я передаю их моему AppWidget, что новые данные были найдены, передавая эти данные как массив целых чисел в намерении.

Мой метод onReceive в моем AppWidgetProvider извлекает эти данные, и затем я прохожу процесс установки нового намерения, которое передается моим RemoteViews для AppWidget. Пример кода ниже:

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, но как мне получить доступ к намерению, которое я передал из onReceive AppWidget?

Буду признателен за понимание того, как правильно это делать. Спасибо.

Ответы [ 4 ]

5 голосов
/ 13 сентября 2011

Мое решение для целочисленного массива, передаваемого в RemoteViewsFactory, было решено с помощью BroadcastReceiver. Я расширил свой RemoteViewsFactory для реализации BroadcastReceiver (в частности, onReceive) и зарегистрировал его в своем приложении в конструкторе для фабрики (это также означает, что я зарегистрировал его в onDestroy). После этого я смог передать намерение с помощью целочисленного массива, который был в onReceive моего AppWidgetProvider, и получить его в RemoteViewsFactory.

Не забудьте также вызвать AppWidgetManager notifyAppWidgetViewDataChanged, чтобы RemoteViewsFactory знал, что данные, которые он использовал ранее, был признан недействительным, и представлен новый целочисленный массив для создания новых RemoteViews.

3 голосов
/ 16 июня 2012

Чтобы более подробно остановиться на приведенном выше решении Стива в интересах arne.jans и других, я реализовал решение Стивена следующим образом:

  • Извлечение StackRemoteViewsFactory в собственный файл класса
  • Расширение его с помощью BroadcastReceiver
  • Реализация метода onReceive() для сохранения новых данных в статической переменной, к которой класс StackRemoteViewsFactory может также обращаться, когда его getViewAt требует данные
  • Передача всех идентификаторов виджетов через Intent, чтобы я мог вызвать notifyAndUpdate ВСЕХ виджетов в методе onReceive().
  • Наконец, я добавил стандартное определение для приемника в AndroidManifest.xml
2 голосов
/ 18 апреля 2013

Я не расширил RemoteViewFactory с помощью BroadcastReceiver, но реализовал на нем динамический 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;
        }
    }
}
1 голос
/ 03 декабря 2013

Другой альтернативой является использование файловой системы или базы данных sqlite, например,

В AppWidgetProvider:

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

В RemoteViewsService:

 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
 } 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...