如何从 JobIntentService 中删除重复的意图
Posted
技术标签:
【中文标题】如何从 JobIntentService 中删除重复的意图【英文标题】:How to remove duplicate intent from JobIntentService 【发布时间】:2019-11-13 15:23:44 【问题描述】:我有一个JobIntentService
,每次推送通知进来时都会启动它,告诉服务去获取更多数据。当应用程序在前台时,一切正常。
当应用程序在后台并且有多个推送通知进来时,intent 会排队并多次执行相同的intent 给服务器带来不必要的压力,因为对服务器的第一次调用将获得它需要的所有信息使推送通知中的其他排队意图变得不必要。
是否有取消或不将相同的意图添加到队列或其他方式来防止对服务器的额外调用?
【问题讨论】:
您能否使用诸如每次执行服务时存储的时间戳之类的东西,并使用它来确保它在 n 分钟内执行的次数不超过 x 次? 怎么样:我们创建 1 个待处理意图列表,在enqueueWork
内部我们检查列表待处理意图是否包含新工作,如果它包含,那么我们不排队工作(我们检查它是否包含例如,向意图添加 1 个属性)。在onHandleWork
中,当它完成时,我们从待处理的意图列表中删除意图
@PhanVanLinh 嗯,有趣的想法,我可以只保留待处理操作的列表(或者甚至只是检查推送通知发生的特定操作,以防止由于此更改而弹出其他错误)然后在句柄工作发生时将其从列表中删除
“当应用程序在前台时,一切正常”这是否意味着如果 fg 那么它会自动工作,或者它只是在旧的工作完成之前没有收到下一个工作?
@MarianPaździoch 表示意图不会排队,因为它们会立即执行,因此应用程序附带的任何推送通知都是 fg 将导致合法数据与应用程序是 bg 并进入多个通知,意图队列,当第一个意图被执行时,它会抓取第一个意图中的所有数据,任何后续的服务器调用都不会返回任何数据
【参考方案1】:
因此,首先提出几个已经相似且知识渊博的问题:question1 和 question2。也许您的问题甚至重复了类似的问题。
最干净的方法是在 MyOwnJobIntentService extends JobIntentService
中处理 JobIntentService 的作业队列。
在androidx.core.app.JobIntentService.java
中有:
final ArrayList<CompatWorkItem> mCompatQueue;
在你的MyOwnJobIntentService extends JobIntentService
:
if(mCompatQueue.isEmpty())
//only in this case enqueue new job
但不幸的是,mCompatQueue
不是公共字段。
10 分钟后,我们得到了有效的解决方案 -> SingleJobIntentService
一个 JobIntentService,如果它已经在工作,它将不会对作业进行排队。
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.app.JobIntentService;
import android.util.Log;
public class SingleJobIntentService extends JobIntentService
private static final String TAG = "SingleJobIntentService";
private Intent theOnlyJobIhave = null;
public static void enqueue(Context context, Intent work)
Log.d(TAG, "enqueue: someone tries to add me work " + work.hashCode());
JobIntentService.enqueueWork(
context,
SingleJobIntentService.class,
SingleJobIntentService.class.hashCode(),
work);
@Override
protected void onHandleWork(@NonNull final Intent theWorkIgot)
Log.d(TAG, "onHandleWork: " + this.hashCode());
if (theOnlyJobIhave == null)
theOnlyJobIhave = theWorkIgot;
final int extraValue = theOnlyJobIhave.getIntExtra(MainActivity.KEY, -500);
Log.d(TAG, "onHandleWork: " + extraValue);
try
Thread.sleep(7000); //this simulates fetch to server
catch (InterruptedException e)
e.printStackTrace();
else
Log.d(TAG, "onHandleWork I'm already busy, refuse to work >:(");
Log.d(TAG, "onHandleWork end");
你可能想用一个简单的按钮来测试它:
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
public class MainActivity extends AppCompatActivity
public static final String KEY = "KEYKEY";
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new OnClickListener()
@Override
public void onClick(final View v)
final Intent theIntent = new Intent();
theIntent.putExtra(KEY, 666);
SingleJobIntentService.enqueue(MainActivity.this, theIntent);
);
注意:你必须小心线程,因为我给出的解决方案不是线程安全的。例如在 编辑: 在考虑之后 -> 因为androidx.core.app.JobIntentService.java
中,触摸mCompatQueue
是同步的。onHandleWork
是从单线程的 JobIntentService 调用的,所以没有线程问题,并且解决方案是线程安全的!
【讨论】:
【参考方案2】:您可以对所有通知使用相同的通知 ID,这样它将覆盖旧通知并为您提供唯一具有最新意图的最新通知。
如果您有针对不同操作的多种类型的通知,您可以创建不同的通知组,提供仅适用于特殊类型操作的意图。
并且还要继续清除通知组,这样一旦单击其中一个通知,您就可以清除同一组通知。
【讨论】:
这根本不是关于通知 API,而是关于发送到 JobIntentService 并排队的多个意图以上是关于如何从 JobIntentService 中删除重复的意图的主要内容,如果未能解决你的问题,请参考以下文章
如何在通过广播接收器将 JobIntentService 之间的数据传递给活动时防止 TransactionTooLarge 异常
我们如何在 Scala 中使用 android JobIntentService?
从 IntentService 迁移到 Android O 的 JobIntentService
IntentService 已弃用,如何将其替换为 JobIntentService?