targetSdkVersion 26 giving exception in crash reports

╄→гoц情女王★ 提交于 2019-12-02 13:59:10

问题


As per the requirement to update targeted SDK version to 26 by November 2018, I tried to update my gradle file a few months ago and released a new version of my app, after updating both target sdk and compile sdk versions to 26 (from 23). Within a day, I started observing crashes in my app on my Firebase console. The reason was I was using TTS service in my app, and when targeting to version 26, it looks like it required a new implementation for the TTS service, because of the fatal run-time exception. So I reverted the target SDK version to 23 and compile sdk version to 23.

Caused by java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.a.b.c/services.TTSService }: app is in background

This exception was seen only for the devices on Android OS 8.0 and 8.1.

So a month ago, I bought a new device which is on Android 8.0 (Motorola G6 Plus), hoping to consistently reproduce this error. But it never happened on this device, even though my app targeting version 26, even when I forcefully triggered the TTS service through my app. So, I am confused as to how to proceed.

The solution for this exception is explained here.

My current code for implementing and calling the TTS service is as follows:

MainActivity oncreate method :

 if(!isMyServiceRunning(TTSService.class))//Start a service instance only if service is currently not running
        startService(new Intent(MainActivity.this, TTSService.class));

TTSService.java:

package services;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;  
import android.os.Environment;
import android.os.IBinder;
import android.speech.tts.TextToSpeech;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;

import com.google.firebase.crash.FirebaseCrash;

import constants.ConstantParams;

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();
        FirebaseCrash.report(new Exception("Error in initializing TTS object"));
        FirebaseCrash.log("Error in initializing TTS object");
    }


    return Service.START_STICKY;
}

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

}

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

}

Do I have to re-implement this feature as per the above mentioned solution? Or can I resort to a simpler approach of targeting the version 26 SDK, but retaining compile SDK version at 23 (it's current state in my app)? Any other solutions would be appreciated.


回答1:


Android 8.0+ doesn't allow background service to be started. Please refer to this for a better understanding of what is the cause of the problem. You can migrate to either FirebaseJobDispatcher or JobScheduler depending on what is your minSdkVersion. Also, in case you use androidx - WorkManager.

P.S. Note that notification won't work as well after set target SDK to 26.




回答2:


On android 8(api 26)+ you unable to run services in background. Thing you can do it is to run service in foreground by adding permission service foreground in manifest and by calling startServiceForeground().




回答3:


Can you please try this

 `startForegroundService()` in place  of `startService()`.



回答4:


I Change your service code . check this out (follow //ADD THIS comments)

Add follow function to your service

//ADD THIS
private IBinder mBinder = new LocalBinder();

//ADD THIS
@Override
public IBinder onBind(Intent intent) {
    // Called when a client (MainActivity in case of this sample) comes to the foreground
    // and binds with this service. The service should cease to be a foreground service
    // when that happens.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        stopForeground(true);
    }
    return mBinder;
}

//ADD THIS
@Override
public void onRebind(Intent intent) {
    // Called when a client (MainActivity in case of this sample) returns to the foreground
    // and binds once again with this service. The service should cease to be a foreground
    // service when that happens.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        stopForeground(true);
    }
    super.onRebind(intent);
}
//ADD THIS
@Override
public boolean onUnbind(Intent intent) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForeground(13, new Notification());
        return true; // Ensures onRebind() is called when a client re-binds.
    }
    return false;
}

//ADD THIS
public class LocalBinder extends Binder {
    public TTSService getServerInstance() {
        return TTSService.this;
    }
}

And in your MainActivity add this variables upper onCreate()

// A reference to the service used to get location updates.
private TTSService mService = null;
// Tracks the bound state of the service.
private boolean mBound = false;

// Monitors the state of the connection to the service.
private final ServiceConnection mServiceConnection = new ServiceConnection() {

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            TTSService.LocalBinder binder = (TTSService.LocalBinder) service;
            mService = binder.getServerInstance();
            mBound = true;
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            mService = null;
            mBound = false;
        }
    }
};

And add below lines in onStop() and onStart()

@Override
protected void onStop() {
    super.onStop();

    //add for android O
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        if (mBound) {
            // Unbind from the service. This signals to the service that this activity is no longer
            // in the foreground, and the service can respond by promoting itself to a foreground
            // service.
            unbindService(mServiceConnection);
            mBound = false;
        }
    }

}

@Override
protected void onStart() {
    super.onStart();


    //add for android O
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        bindService(new Intent(this, TTSService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
    }
}

Hope it's help



来源:https://stackoverflow.com/questions/51687080/targetsdkversion-26-giving-exception-in-crash-reports

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!