【问题标题】:How to make activity to show data got from the service?如何进行活动以显示从服务获取的数据?
【发布时间】:2018-07-01 09:53:17
【问题描述】:

我需要编写一个服务,该服务将每 30 秒更新一次 MainActivity 中的列表。我将 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());

}

当 JobService 中的 Onchanged 起作用时,我会得到列表并显示通知。通知会打开 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);
        }
    }

【问题讨论】:

  • I use MVVM with ViewModel and LiveData and so my Service class looks like this: 我完全不明白为什么你的服务类看起来像那样
  • 如果我能做得更好,我不会问这个问题并寻求建议,所以要么提出建议和更正,要么非常具体,要么不要发表任何评论
  • 我的意思是,除了获取服务中的项目列表之外,您的服务究竟做了什么,然后显示通知?我想“更新列表”意味着获取写入 Room 的数据,一旦完成,订阅 LiveData&lt;List&lt;T&gt;&gt; 将自动更新列表,而无需在后台线程上执行任何操作。您的要求不明确。
  • 所以要求是运行后台服务,每 30 秒从 web 服务获取数据并显示通知,打开通知显示更新的主屏幕。我的服务现在所做的只是从服务器获取数据,我不明白如何将它与 MainActivity 绑定。关于房间,它不是我的应用程序中的事实来源,我在插入带有 LiveData 的房间时遇到问题,所以我使用带有通用列表的房间,我将提供 repo 代码
  • 编辑问题并添加回购代码

标签: java android kotlin android-livedata android-mvvm


【解决方案1】:

你有这个问题特别因为你的存储库实现不正确。

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)是在 Repository 上有两个单独的函数:一个用于fetchFromNetwork,一个用于fetchFromDatabase。 MainActivity 应始终从数据库中获取,而 Service 始终触发从网络加载(并通过 Dao 将其直接插入数据库)。

这样,当Service在后台线程将数据插入DB时,MainActivity中的observe函数会收到最新的数据。

【讨论】:

  • 非常感谢,我正在考虑分别调用 db 和 webservice,但你说得更清楚了,我也更有信心了。我唯一关心的是我应该如何组织分页,目前每次到达列表末尾时它都会从网络加载,每次达到页面大小时我都会清除数据库 * 2
  • 如果涉及到分页,您可能希望从您的 DAO 中公开DataSource.Factory,并在您的 LivePagedListBuilder 上设置一个 BoundaryCallback(使用分页 AAC)。这样您就可以在滚动到页面底部时启动后台抓取任务。
  • 我很怕我在 Paging Library 上花了 3-4 天都不能让它工作,我的截止日期是明天,所以我想我会手工实现 paging library 的概念。
  • 嗯,如果您放弃了 Paging,那么您可以使用object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { if (!recyclerView.canScrollVertically(1)) { onScrolledToBottom() } } 来检测您何时处于页面底部,并启动后台获取任务(如果尚未进行)
  • 我已经做了那部分,到达底部并从网络获取数据,我的 api 确实提供了页码和页面大小,我关心的是从分页库中逐页获取数据。
猜你喜欢
  • 1970-01-01
  • 2013-08-10
  • 1970-01-01
  • 2013-03-10
  • 1970-01-01
  • 1970-01-01
  • 2021-04-03
  • 1970-01-01
  • 2013-01-16
相关资源
最近更新 更多