Сбой API JobScheduler на устройствах Android 8.0 - PullRequest
0 голосов
/ 06 октября 2018

Для удовлетворения требований целевого приложения Android API 26 для моего приложения я изменил фоновую службу в своем приложении, чтобы она запускалась с помощью JobScheduler вместо простой службы.Вот мой обновленный код.

В моем классе PhoneUtils

 public static void scheduleTTSJob(Context context) {

    if(isTTSJobServiceOn(context))
    {
        return;
    }

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {

        ComponentName serviceComponent = new ComponentName(context, TTSJobScheduledService.class);
        JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, serviceComponent);

        builder.setMinimumLatency(1 * 1000); // wait at least
        builder.setOverrideDeadline(3 * 1000); // maximum delay
        JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
        jobScheduler.schedule(builder.build());
    }
}

public static boolean isTTSJobServiceOn( Context context ) {

    boolean hasBeenScheduled = false;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

        JobScheduler scheduler = (JobScheduler) context.getSystemService( Context.JOB_SCHEDULER_SERVICE );

        for ( JobInfo jobInfo : scheduler.getAllPendingJobs() ) {
            if ( jobInfo.getId() == JOB_ID ) {
                hasBeenScheduled = true;
                break;
            }
        }
    }

    return hasBeenScheduled;
}

public static void stopTTSJob(Context context)
{
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        JobScheduler scheduler = (JobScheduler) context.getSystemService( Context.JOB_SCHEDULER_SERVICE );

        for ( JobInfo jobInfo : scheduler.getAllPendingJobs() ) {
            if ( jobInfo.getId() == JOB_ID ) {

                scheduler.cancel(JOB_ID);
                break;
            }
        }
    }
}

TTSJobScheduledService class

package services;

import android.annotation.TargetApi;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.Intent;
import android.os.Build;

import utilities.PhoneUtils;

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class TTSJobScheduledService extends JobService {

@Override
public boolean onStartJob(JobParameters params) {
    Intent service = new Intent(getApplicationContext(), TTSService.class);
    getApplicationContext().startService(service);
    PhoneUtils.scheduleTTSJob(getApplicationContext()); // reschedule the job
    return true;
}

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

Код для класса TTSService:

package services;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.speech.tts.TextToSpeech;
import android.support.annotation.Nullable;

public class TTSService extends Service {

   private static TextToSpeech voice =null;

   public static TextToSpeech getVoice() {
    return voice;
}

@Nullable
@Override

public IBinder onBind(Intent intent) {
    // not supporting binding
    return null;
}

public TTSService() {
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    try{

            voice = new TextToSpeech(TTSService.this, new TextToSpeech.OnInitListener() {
                @Override
                public void onInit(final int status) {

                }
            });
    }
    catch(Exception e){
        e.printStackTrace();
    }


    return Service.START_STICKY;
}

@Override
public void onDestroy() {
    clearTtsEngine();
    super.onDestroy();

}

public static void clearTtsEngine()
{
    if(voice!=null)
    {
        voice.stop();
        voice.shutdown();
        voice = null;
    }
}
}

Кроме того, я добавил эту новую службу в свой файл манифеста:

<service
        android:name="services.TTSJobScheduledService"
        android:label="TTS service"
        android:permission="android.permission.BIND_JOB_SERVICE" >

</service>

Я планирую эту службу, когда пользователь открывает мое приложение(если это еще не запланировано), или если устройство перезагружено, или если приложение обновлено в Google Play.

Однако вскоре после того, как я выпустил это обновление приложения, у меня начались сбои с этой трассировкой стека для устройств.с Android 8.0.0 и выше:

Caused by java.lang.IllegalStateException: Not allowed to start service Intent { cmp=abc.fgh.com.abc/services.TTSService }: app is in background uid UidRecord{6dafcbe u0a250 TRNB idle procs:1 seq(0,0,0)}
   at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1505)
   at android.app.ContextImpl.startService(ContextImpl.java:1461)
   at android.content.ContextWrapper.startService(ContextWrapper.java:644)
   at services.TTSJobScheduledService.onStartJob(Unknown Source:15)
   at android.app.job.JobService$1.onStartJob(JobService.java:71)
   at android.app.job.JobServiceEngine$JobHandler.handleMessage(JobServiceEngine.java:108)
   at android.os.Handler.dispatchMessage(Handler.java:105)
   at android.os.Looper.loop(Looper.java:180)
   at android.app.ActivityThread.main(ActivityThread.java:6950)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:835)

Как я понимаю, этого не должно происходить, если я использую вызов JobScheduledService scheduleTTSJob (), а не простой вызов startService () из моего кода.Он не зависал на устройстве, которое я тестировал (Moto G6), на котором также установлен Android 8.0.0, но теперь происходит сбой на этих других устройствах с Android 8.0.0 и выше.

1 Ответ

0 голосов
/ 06 октября 2018

Как я понимаю, этого не должно происходить, учитывая, что я использую вызов JobScHeduledService scheduleTTSJob (), а не простой вызов startService () из моего кода

Вы определенно используетепростой startService() звонок из вашего кода.Это в вашем onStartJob() методе:

@Override
public boolean onStartJob(JobParameters params) {
    Intent service = new Intent(getApplicationContext(), TTSService.class);
    getApplicationContext().startService(service);
    PhoneUtils.scheduleTTSJob(getApplicationContext()); // reschedule the job
    return true;
}

, и именно здесь трассировка стека показывает, что у вас сбой.

Пожалуйста, дайте мне знать, что это за исправлениесделано в моем коде

Либо:

  • Удалить этот startService() вызов, либо

  • Использовать ContextCompat.startForegroundService() и TTSService вызовите startForeground() при запуске или

  • Если применимо, переместите эту логику TTSService в некоторый не обслуживающий код в выполняемом фоновом потокенепосредственно из onStartJob()

Трудно дать вам более конкретный совет, учитывая, что мы не знаем, что такое TTSService.

...