sunflower20
sunflower20

Reputation: 499

How to make activity to show data got from the service?

I need write a service which will update the list in MainActivity every 30sec. I use MVVM with ViewModel and LiveData and so my Service class looks like this:

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;
    }
}

Class for my notification:

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());

}

When Onchanged in JobService works I get the list and show a notification. Notification opens MainActivity which makes new call to api as it always did. What changes do I have to make in order the MainActivity to show the list that I got from the service??? I really can't tie this up together. I heard of IPC but wouldn't do that, I want some simpler practice which I sure exists which I just don't know about. Also, there are two cases: Notification came and MainActivity is open, app is open but MainActivity is not in the foreground and app is on the background or closed. How should I handle each of these cases?

See also piece of code from 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;

Please provide the best practices for this task, I know it's very common I just do it first time and using LiveData makes it way more complicated.

Here is Also Repository code:

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);
        }
    }

Upvotes: 0

Views: 772

Answers (1)

EpicPandaForce
EpicPandaForce

Reputation: 81549

You have this problem specifically because your Repository implementation is incorrect.

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);
    }
}

If you check the code for NetworkBoundResource, the trick is that you have a single LiveData that binds together the ability to both load from network, and to load from database.

In your case, you are replacing the database's auto-updating query results whenever you have network access - which is why you can't update the MainActivity.

The easiest way (without using a MediatorLiveData) is to have two separate functions on Repository: one for fetchFromNetwork, and one for fetchFromDatabase. The MainActivity should always fetch from database, while the Service always triggers load from network (and inserts it directly into database via a Dao).

This way, the observe function in MainActivity will receive the latest data when Service inserts the data into DB on background thread.

Upvotes: 1

Related Questions