在应用程序启动时,应用程序启动应该执行一些网络任务的服务。 在目标API级别26后,我的应用程序无法在Android 8.0后台启动服务。

导致原因:java.lang.IllegalStateException:不允许启动 服务意图{ cmp = my.app.tt / com.my.service }: app是在后台uid UidRecord{90372b1 u0a136 CEM空闲procs:1 seq (0, 0, 0)}

我的理解是: 后台执行限制

startService()方法现在抛出一个IllegalStateException 针对Android 8.0的应用程序尝试使用这种方法 不允许创建后台服务。

“在不被允许的情况下”——这实际上是什么意思?以及如何修复它。我不想把我的服务设置为前台


当前回答

备选方案使用JobScheduler,它可以定时在后台启动服务。

首先将类命名为Util.java

import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;

public class Util {
// schedule the start of the service every 10 - 30 seconds
public static void schedulerJob(Context context) {
    ComponentName serviceComponent = new ComponentName(context,TestJobService.class);
    JobInfo.Builder builder = new JobInfo.Builder(0,serviceComponent);
    builder.setMinimumLatency(1*1000);    // wait at least
    builder.setOverrideDeadline(3*1000);  //delay time
    builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);  // require unmetered network
    builder.setRequiresCharging(false);  // we don't care if the device is charging or not
    builder.setRequiresDeviceIdle(true); // device should be idle
    System.out.println("(scheduler Job");

    JobScheduler jobScheduler = null;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        jobScheduler = context.getSystemService(JobScheduler.class);
    }
    jobScheduler.schedule(builder.build());
   }
  }

然后,将JobService类命名为TestJobService.java

import android.app.job.JobParameters;
import android.app.job.JobService;
import android.widget.Toast;
 
  /**
   * JobService to be scheduled by the JobScheduler.
   * start another service
   */ 
public class TestJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
    Util.schedulerJob(getApplicationContext()); // reschedule the job
    Toast.makeText(this, "Bg Service", Toast.LENGTH_SHORT).show();
    return true;
}

@Override
public boolean onStopJob(JobParameters params) {
    return true;
  }
 }

在名为servicerreceiver .java的BroadCast Receiver类之后

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

 public class ServiceReceiver extends BroadcastReceiver {
 @Override
public void onReceive(Context context, Intent intent) {
    Util.schedulerJob(context);
 }
}

用服务和接收器类代码更新清单文件

<receiver android:name=".ServiceReceiver" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    <service
        android:name=".TestJobService"
        android:label="Word service"
        android:permission="android.permission.BIND_JOB_SERVICE" >

    </service>

将main_intent启动器留在默认创建的mainActivity.java文件中,mainActivity.java文件中的更改是

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Util.schedulerJob(getApplicationContext());
  }
 }

WOOAAH ! !后台服务启动时没有前台服务

[编辑]:你可以使用工作管理器的任何类型的Android后台任务。

其他回答

如果你有集成的firebase消息推送通知,

由于后台执行限制,为android O (android 8.0)添加新的/更新firebase消息依赖项。

compile 'com.google.firebase:firebase-messaging:11.4.0'

如果需要,升级谷歌播放服务和谷歌存储库。

更新:

 compile 'com.google.firebase:firebase-messaging:11.4.2'

如果服务通过扩展IntentService运行在后台线程中,你可以用JobIntentService替换IntentService, JobIntentService是Android支持库的一部分

使用JobIntentService的优点是,它在pre-O设备上表现为IntentService,在O或更高的设备上,它作为作业分派

JobScheduler还可以用于定期/按需作业。但是,确保处理向后兼容性,因为JobScheduler API仅从API 21可用

是的,那是因为在API 26上你不能在后台启动服务了。所以你可以在API 26之上启动ForegroundService。

你必须使用

ContextCompat.startForegroundService(...)

并在处理泄漏时发布通知。

由于对这个答案的争议投票(+4/-4),请先看看其他答案,并仅作为最后的手段。我只在一个以root身份运行的网络应用程序中使用过一次,我同意一般的意见,即在正常情况下不应该使用这种解决方案。

原答案如下:

其他答案都是正确的,但我想指出的是,另一种解决这个问题的方法是要求用户禁用应用程序的电池优化(这通常不是一个好主意,除非你的应用程序与系统相关)。看看这个答案如何请求选择退出电池优化而不让你的应用程序在谷歌播放被禁止。

你也应该检查电池优化是否在你的接收器关闭,以防止崩溃通过:

if (Build.VERSION.SDK_INT < 26 || getSystemService<PowerManager>()
        ?.isIgnoringBatteryOptimizations(packageName) != false) {
    startService(Intent(context, MyService::class.java))
} // else calling startService will result in crash

如果任何意图之前工作正常时,应用程序是在后台,这将不再是Android 8及以上的情况下。只引用意图,当app在后台时,它必须做一些处理。

必须遵循以下步骤:

Above mentioned intent should be using JobIntentService instead of IntentService. The class which extends JobIntentService should implement the - onHandleWork(@NonNull Intent intent) method and should have below the method, which will invoke the onHandleWork method: public static void enqueueWork(Context context, Intent work) { enqueueWork(context, xyz.class, 123, work); } Call enqueueWork(Context, intent) from the class where your intent is defined. Sample code: Public class A { ... ... Intent intent = new Intent(Context, B.class); //startService(intent); B.enqueueWork(Context, intent); }

下面的类以前扩展了Service类

Public Class B extends JobIntentService{
...

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, B.class, JobId, work);
    }

    protected void onHandleWork(@NonNull Intent intent) {
        ...
        ...
    }
}

com.android。支持:支持compat需要JobIntentService -我使用26.1.0 V。 最重要的是确保Firebase库的版本至少是10.2.1,我在10.2.0有问题——如果你有的话! 你的manifest应该具有Service类的以下权限: 服务android: name = "。B” android:出口= " false " android:许可= " android.permission.BIND_JOB_SERVICE "

希望这能有所帮助。