如何从JobIntentService中删除重复意图

8
我有一个JobIntentService,每次收到推送通知时都会启动该服务以告诉服务去获取更多的数据。当应用程序在前台时,一切正常。
当应用程序在后台运行且多个推送通知到达时,该意图被排队执行多次,这将给服务器带来不必要的压力,因为对服务器的第一次调用将获得所有所需信息,从推送通知中排队的其他意图则是不必要的。
有没有办法取消或不将相同的意图添加到队列中,或者通过其他方式防止对服务器的额外调用?

你能否使用一个时间戳来记录每次执行服务的时间,并确保它在n分钟内不会被执行超过x次? - fjc
我们可以这样做:创建一个待处理意图列表,在enqueueWork内部,我们检查列表中是否包含新的任务,如果包含,则不进行enqueueWork(例如,我们可以为意图添加1个属性来检查是否包含)。在onHandleWork中,当任务完成后,我们将其从待处理意图列表中移除。 - Linh
1
@PhanVanLinh 嗯,有趣的想法,我可以只保留一个待处理操作列表(甚至只是检查针对推送通知发生的特定操作),以防止由于此更改而弹出其他错误,并在处理操作完成后从列表中删除它。 - tyczj
当应用程序在前台时,一切都按照预期工作,这是否意味着如果在前台,则自动工作,或者只是在旧任务完成之前不接收下一个任务? - Marian Paździoch
@MarianPaździoch 的意思是,意图不会排队,因为它们立即执行,所以任何在应用程序前台推送的通知都会导致合法数据,而在应用程序后台时,多个通知会排队,当第一个意图被执行时,它会获取第一个意图中的所有数据,并且任何随后的服务器调用将返回零数据。 - tyczj
2个回答

3

首先,有几个与此类似的问题包含了很多有用的知识:question1question2。也许你的问题甚至与这些相似。

最简单的方法是在你的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的多个意图排队的问题。 - tyczj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接