Как сделать так, чтобы данные отображались с сервиса? - PullRequest
0 голосов
/ 01 июля 2018

Мне нужно написать сервис, который будет обновлять список в MainActivity каждые 30 секунд. Я использую MVVM с ViewModel и LiveData, поэтому мой класс Service выглядит следующим образом:

public class ArticleJobService extends JobService {

    public static String TAG = "ArticleJobService";

    private Context context = this;

    @Override
    public boolean onStartJob(JobParameters jobParameters) {
        Log.d(TAG, "onStartJob");
        MainActivity.PAGE_NUMBER++;
        LiveData<List<Article>> liveArticles = ArticleRepository.getInstance(getApplication()).getArticles(MainActivity.PAGE_NUMBER);

        liveArticles.observeForever(new Observer<List<Article>>() {
            @Override
            public void onChanged(@Nullable List<Article> articles) {
                Log.d(TAG, "onStartJob - onChanged!!!!!!");
                liveArticles.removeObserver(this);
                NotificationUtils.showNotification(context, articles.get(0).getSectionName(), articles.get(0).getWebTitle());
                jobFinished(jobParameters, true);
            }
        });
        return true;
    }
}

Класс для моего уведомления:

public static void showNotification(Context context, String section, String title) {
    PendingIntent contentPendingIntent = PendingIntent.getActivity
            (context, REQUEST_CODE, new Intent(context, MainActivity.class),
                    PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationManager manager =
            (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);


    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        manager.createNotificationChannel(createNotificationChannel(context));
    }

    NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
            .setContentTitle(section)
            .setContentText(title)
            .setContentIntent(contentPendingIntent)
            .setSmallIcon(R.drawable.app_icon)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setDefaults(NotificationCompat.DEFAULT_ALL)
            .setAutoCancel(true);

    manager.notify(0, builder.build());

}

Когда работает Onoted в JobService, я получаю список и показываю уведомление. Уведомление открывает MainActivity, что делает новый вызов API, как и всегда. Какие изменения я должен сделать, чтобы MainActivity отображал список, полученный от службы ??? Я действительно не могу связать это вместе. Я слышал о IPC, но не буду этого делать, я хочу более простую практику, которая, я уверен, существует, о которой я просто не знаю. Кроме того, есть два случая: пришло уведомление, и MainActivity открыта, приложение открыто, но MainActivity не находится на переднем плане, а приложение находится в фоновом режиме или закрыто. Как мне обращаться с каждым из этих случаев?

См. Также фрагмент кода из MainActivity onCreate:

 mArticleViewModel = ViewModelProviders.of(this).get(ArticleViewModel.class);
    mArticleViewModel.getArticleList(PAGE_NUMBER).observe(this, articles -> {
        Log.d(TAG, "List<Result> onChanged!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        mProgressBar.setVisibility(View.GONE);
        mProgressBarMain.setVisibility(View.GONE);
        mIsLoading = false;
        mArticles = articles;

Пожалуйста, предоставьте лучшие практики для этой задачи, я знаю, что это очень часто, я просто делаю это в первый раз, и использование LiveData усложняет задачу.

Вот также код репозитория:

public static ArticleRepository getInstance(Application application){
        if(INSTANCE == null){
            return  new ArticleRepository(application);
        }

        return INSTANCE;
    }

    private ArticleRepository(Application application) {
        Log.d(TAG, "ArticleRepository constructor");
        mContext = application;
        mArticles = new MutableLiveData<>();
        ArticleRoomDatabase db = ArticleRoomDatabase.getInstance(application);
        mArticleDao = db.articleDao();
    }

    public LiveData<List<Article>> getArticles(int page) {
        Log.d(TAG, "getArticles");
        if (NetworkUtils.isOnline(mContext)) {
            Log.d(TAG, "isOnline");
            mArticles = loadFromNetwork(page);
        } else {
            Log.d(TAG, "is NOT Online");
            mArticles = loadFromDB(page);
        }
    }

1 Ответ

0 голосов
/ 01 июля 2018

У вас есть эта проблема, в частности , потому что ваша реализация репозитория неверна.

public LiveData<List<Article>> getArticles(int page) {
    Log.d(TAG, "getArticles");
    if (NetworkUtils.isOnline(mContext)) {
        Log.d(TAG, "isOnline");
        mArticles = loadFromNetwork(page);
    } else {
        Log.d(TAG, "is NOT Online");
        mArticles = loadFromDB(page);
    }
}

Если вы проверите код для NetworkBoundResource , уловка заключается в том, что у вас есть одна LiveData, которая связывает воедино возможность загрузки из сети и загрузки из базы данных.

В вашем случае вы заменяете результаты запроса автообновления базы данных всякий раз, когда у вас есть доступ к сети, поэтому вы не можете обновить MainActivity.

Самый простой способ (без использования MediatorLiveData) - это две отдельные функции в репозитории: одна для fetchFromNetwork, а другая для fetchFromDatabase. MainActivity всегда должна извлекать данные из базы данных, а служба всегда инициирует загрузку из сети (и вставляет ее непосредственно в базу данных через Dao).

Таким образом, функция observe в MainActivity будет получать самые последние данные, когда Сервис вставляет данные в БД в фоновом потоке.

...