【问题标题】:Android Oreo JobIntentService Keep running in background for Android 7 &below and crashing often in Android 8 & aboveAndroid Oreo JobIntentService 在 Android 7 及以下版本中继续在后台运行,在 Android 8 及以上版本中经常崩溃
【发布时间】:2019-01-08 17:04:05
【问题描述】:

我最近将我的所有服务替换为前台服务和 JobIntentService,因为在 oreo 及更高版本中存在一些后台执行限制 (https://developer.android.com/about/versions/oreo/background)。根据文档,JobIntentService 的作用类似于 Android 7 及更低版本的 Intent Service,并且类似于 Android 8 及更高版本的 JobScheduler。我注意到 Google 提供的新 JobIntentService 存在问题。

Android 8 及更高版本:

在 android 8 及更高版本中不断发生崩溃。这里提出了一张票,提到了同样的问题https://issuetracker.google.com/issues/63622293,我添加了一些极客建议的临时修复。

Android 7 及以下: JobIntentService 在工作完成后不会停止,就像 Intent Service 一样。

我在服务中实现了 JobIntentService,只要用户执行某些操作就会触发。

代码

public class SampleJobIntentService extends FixedJobIntentService {

public static void postData(Context context, String data) {
    Intent intent = new Intent(context, SampleJobIntentService.class);
            intent.setAction(INITIAL_ACTION);
            intent.putExtra(SAMPLE_ID, data);
            SampleJobIntentService.enqueueWork(context,intent);
}

public static void enqueueWork(Context context, Intent work) {
    SampleJobIntentService.enqueueWork(context, SampleJobIntentService.class, JOB_ID, work);

 @Override
    protected void onHandleWork(@NonNull Intent intent) {
        if (intent != null) {
            SampleRequest sampleRequest = requests.get(intent.getAction());
            if (sampleRequest != null) {
                try {
                   // perform some networking operations
                } catch (Exception ex) {
                    Log.d("Error for intent ");
                }
                Log.i("send action ");
            } else
                Log.e("action not found for ");
        }
    }
    }

为了避免 JobIntentService 崩溃,我从https://issuetracker.google.com/issues/63622293 中引用了一些参考资料

public abstract class FixedJobIntentService extends JobIntentService {

    @Override
    GenericWorkItem dequeueWork() {
        try {
            return new FixedGenericWorkItem(super.dequeueWork());
        } catch (SecurityException ignored) {
            doStopCurrentWork();
        }
        return null;
    }

    private class FixedGenericWorkItem implements GenericWorkItem {
        final GenericWorkItem mGenericWorkItem;

        FixedGenericWorkItem(GenericWorkItem genericWorkItem) {
            mGenericWorkItem = genericWorkItem;
        }

        @Override
        public Intent getIntent() {
            if (mGenericWorkItem != null) {
                return mGenericWorkItem.getIntent();
            }
            return null;
        }

        @Override
        public void complete() {
            try {
                if (mGenericWorkItem != null) {
                    mGenericWorkItem.complete();
                }
            } catch (IllegalArgumentException ignored) {
                doStopCurrentWork();
            }
        }
    }
}

【问题讨论】:

  • 你为什么要触发一个服务来触发一个 JobIntentService。 JobIntentService 可以直接在用户操作时触发?
  • @Ankur 即使我直接触发 JobIntentService,一旦工作完成,它也不会被杀死。我已经提到了在我的项目中使用它的一种情况。我的项目中使用了几个 JobIntentServices
  • 你能提供你正在使用的JobIntentService的示例代码吗?
  • 我已经更新了我的问题
  • @Kalai.G,好的......我明白了......我正在逐步解释它作为答案......因为我看不到这里剩下多少空间......我不想让完整的线程充满喜欢闲聊。

标签: android intentservice jobintentservice


【解决方案1】:

我认为您只需要这么多代码。创建一个新的 MyJobIntentService 类并编写这么多代码并调用 postData() 来启动您的服务。

public class MyJobIntentService extends JobIntentService {

public static void postData(Context context, String data) {
    final Intent intent = new Intent(context, MyJobIntentService.class);
    intent.setAction(INITIAL_ACTION);
    intent.putExtra(SAMPLE_ID, data);
    enqueueWork(context, MyJobIntentService.class, 1000, intent);
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onDestroy() {
    Ln.d("Cancelled service");
    super.onDestroy();
}

@Override
    protected void onHandleWork(@NonNull Intent intent) {
        if (intent != null) {
            final SampleRequest sampleRequest = requests.get(intent.getAction());
            if (sampleRequest != null) {
                try {
                   // perform some networking operations
                } catch (Exception ex) {
                    Log.d("Error for intent ");
                }
                Log.i("send action ");
            } else {                
               Log.e("action not found for ");
            }
        }
    }
}

并确保在清单文件中添加您的服务

<service
            android:name="service.MyJobIntentService"
            android:exported="false"
            android:permission="android.permission.BIND_JOB_SERVICE" />

【讨论】:

  • 您浏览过这个问题跟踪器吗? issuetracker.google.com/issues/63622293
  • 是的,我已经完整阅读了。但我没有遇到用户的任何崩溃问题。我面临的唯一问题是,如果多次调用它并且它发生在 OREO 设备上,该服务不会启动
  • 确实如此。我的应用程序曾经多次调用发送指标,这种崩溃经常发生。是否测试过在 android 7 及更低版本中工作完成后 JobIntentService 会停止?
  • 根据 cmets 听起来这不是一个有效的答案,或者它没有经过测试?如果是这种情况,则应将其删除。
【解决方案2】:

嗯...,这是一个很大的理论...!它不能把它全部放在这里。我会尽力让你的一些概念清晰。


在阅读谷歌文档方面,我已经失去了整整两年的时间......其中是use-less... 和no proper documentationno proper sample codes for its developers..!!所以我在stack-overflow 上的每个帖子中都提到了这一点,因为这将有助于节省其他人的时间..!!


看起来你是一个优秀的程序员;只需要一些hints to your posted question :

提示 1:

您:- 我最近将所有服务替换为前台服务,并且 JobIntentService

前台服务:

如果您需要ALL THE TIME RUNNING PROCESS; WHICH WILL NEVER END... ONCE IT IS STARTED,它用于从其OnStartCommand 返回START_STICKY 的服务。再次建议不要使用它,就好像您想不惜一切代价实施它一样...然后您将不得不使用带有setOngoing(true) 的通知,最终用户将无法刷掉您的通知,它将永远保留在那里....

前台服务的使用:

对接收器也有限制;在Oreo 以上,您不能通过在清单中声明它并仅制作一个接收器来使用所有接收器和意图操作...我建议只使用BootComplete 权限并使用单个receiver 接收@ 987654333@ 意图并调用 service 如果低于 O 并调用高于 O 的前台服务。现在从该前台服务中为所有人实现运行时接收器并在 Ondestroy 方法中取消注册它。我从来没有找到实现运行时接收器的官方示例代码,最后我通过几个月的努力成功实现了它......是的,由于谷歌,这不是一个聪明的工作

何时使用前台服务:

仅当您想实现广播接收器时......如果您不想实现任何广播接收器;远离......。

提示 2:

您:- 我最近将所有服务替换为前台服务,并且 JobIntentService

** 服务的质量是:**

只是做了一个很小的工作......然后退出......它必须由StopSelf()退出......再次,Services can cause data-loss如果多次调用......因为可以运行相同的服务线程不止一次...再次,如果您想要一项服务做很多工作...使用START_STICKY...但同样不推荐,我已经建议,何时在提示 1 中使用它。

** Intentservice 的质量是:**

做一个运行时间比较长的任务,它有property of execution serially only如果你一次又一次地调用同一个intentService,那么所有的调用都将保存在一个queue中,并在完成one by one之后执行one by one .如上所述,在服务中并非如此。它会自行结束...不需要开发人员来结束它..!!

** 独一无二的品质:**

一旦他们是crashed,android 可以在将来阻止他们调用而不会通知您,因为它会使应用程序崩溃。需要用try-catch-exceptionavoid crash 处理它们。再次...如果you are implementing threads within services 然后try-catch-exception will not save your application from being crashing...

** 那到底是什么以及如何实现它:**

使用FireBaseJobScedular :-

  1. 易于使用
  2. 使用简单的 JobService
  3. 可以运行更长或更短时间的任务...EVEN ALL THE TIME RUNNING TASK
  4. EVEN SUPPORTED BY NON STANDARD COMPANIES like vivo, mi, oppo, one+3, ... 这需要 stock-android 对其进行更改并给出诸如 FunTouchOs、ColorOs、OxygenOs 之类的名称
  5. 只需将电池设置更改为“不优化此应用”
  6. 是的 google 官方支持并推荐使用
  7. 它创建GooglePlyService 的实例并在其中运行,显然非标准公司也不会限制谷歌应用程序执行其任务。
  8. 适用于Oreo ..,即使我已经在Android P 上对其进行了测试,并且在Android 5.0 版以下作为AlarmManager 任务运行。
  9. 我仍然建议使用minsdk above 16target sdk 26,就好像你想将你的应用上传到google play一样,现在这是强制性的,你会听到这个消息。和compile sdk 26
  10. 只需在清单中绑定您的JobService 并使用receive_boot_complete 的单行权限
  11. 只需安排时间...它会在市场上每个制造商的每个设备上启动...甚至在cold boothot boot
  12. 它将大量代码和you can focus on actual tasks 最小化。
  13. 一旦任务完成,您可以return false 表示任务已经完成,它将结束 JobService。

为什么我建议,因为我是CTO的一家井-UNKNOwn公司,并且在许多类型的Android手机制造商中都经历过foreground service引起的问题...不是Apple and ios所以我们必须经历它。自过去 18 年以来一直是开发人员,我今天也主要编写代码......在所有开发项目中,它的开发策略都是我自己考虑的。

更正我......也是......你没有提到what your tasksproject 与...有关 foreground service and intent-service...让我知道...,我很乐意帮助你。这是一个一般的理论答案,而不是你想要的......但是为了给你实际的答案,我需要准确的项目范围......

【讨论】:

  • 感谢您解决我的问题。根据我的项目要求(我不能公开披露),我必须使用前台服务,并且该服务将触发新的 Jobintentservice 发送度量数据并且这不会被自动终止(Intentservice 曾经这样做)。根据您的建议,如果我使用,firebasejobscheduler 这个问题会解决吗?让我试一试。再次感谢一吨
  • 问题将一直存在,直到出现编程和依赖错误/s...仅实现“firebasejobscheduler”并不能解决您的问题...这些是范例...
  • 同意这一点。根据 doc,JobIntentService 将充当意图服务和作业调度程序。我之前使用的 IntentService 将在工作完成后停止,当我替换为 JobIntentService 时并没有在
  • 后台执行限制可以与前台服务或如果您不想要 STICKY 通知,那么应该使用警报管理器...同样,您可以运行长时间运行的任务,但不能运行 FOREVER 任务。再次在每次重新启动时,系统不会记住警报集,因此需要使用数据库处理它,并在再次启动时设置警报...
  • 忘了说 JobIntentService 仍处于 alpha 阶段
【解决方案3】:

工作完成后,像 Intent Service 一样工作的 JobIntentService 不会停止

问题出在您的扩展类 FixedJobIntentService dequeueWork 方法中。

尝试将其更改为如下所示

GenericWorkItem superValue = super.dequeueWork();
if (superValue != null) {
    return new FixedGenericWorkItem(superValue);
}
return null;

查看 JobIntentSerivce 代码,工作项处理器逻辑如下所示,即直到队列中没有工作项为止,所有项目都被处理(即为每个项目调用 onHandleWork)

    while ((work = dequeueWork()) != null) {
        if (DEBUG) Log.d(TAG, "Processing next work: " + work);
        onHandleWork(work.getIntent());
        if (DEBUG) Log.d(TAG, "Completing work: " + work);
        work.complete();
    }

您的实现中的问题是在处理第一个工作项之后,super.dequeueWork() 返回 null,您没有处理它,只是发送一个新的 FixedGenericWorkItem 对象传递 null 值。您可能会观察到在后续调用中将 null 值传递给您的 onHandleWork。

希望这有助于解决您的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多