티스토리 뷰
'java.lang.IllegalStateException: Not allowed to start service Intent' 오류 수정하기
맨날치킨 2022. 12. 19. 11:05Stack Overflow에 자주 검색, 등록되는 문제들과 제가 개발 중 찾아 본 문제들 중에서 나중에도 찾아 볼 것 같은 문제들을 정리하고 있습니다.
Stack Overflow에서 가장 먼저 확인하게 되는 가장 높은 점수를 받은 Solution과 현 시점에 도움이 될 수 있는 가장 최근에 업데이트(최소 점수 확보)된 Solution을 각각 정리하였습니다.
아래 word cloud를 통해 이번 포스팅의 주요 키워드를 미리 확인하세요.
Android 8.0: java.lang.IllegalStateException: Not allowed to start service Intent
안드로이드 8.0: java.lang.IllegalStateException: Not allowed to start service Intent 오류 수정하기
문제 내용
On application launch, app starts the service that should to do some network task. After targeting API level 26, my application fails to start service on Android 8.0 on background.
애플리케이션을 실행하면, 네트워크 작업을 수행해야 하는 서비스가 시작됩니다. 그러나 API 레벨 26을 대상으로 하면서, 백그라운드에서 Android 8.0에서 서비스를 시작하지 못하는 문제가 발생합니다.
Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=my.app.tt/com.my.service }: app is in background uid UidRecord{90372b1 u0a136 CEM idle procs:1 seq(0,0,0)}
as I understand it related to: Background execution limits
내가 이해하기로, 이 문제는 '백그라운드 실행 제한'과 관련이 있는 것 같아.
The startService() method now throws an IllegalStateException if an app targeting Android 8.0 tries to use that method in a situation when it isn't permitted to create background services.
startService() 메서드는 이제 Android 8.0을 대상으로 하는 앱이 백그라운드 서비스를 생성할 수 없는 상황에서 해당 메서드를 사용하려고하면 IllegalStateException을 throw합니다.
"in a situation when it isn't permitted" - what it's actually mean?? And how to fix it. I don't want to set my service as "foreground"
"in a situation when it isn't permitted"은 무엇을 의미하나요?? 그리고 어떻게 고쳐야하나요. 저는 제 서비스를 포그라운드 서비스로 설정 하는 것을 원하지 않습니다.
높은 점수를 받은 Solution
I got solution. For pre-8.0 devices, you have to just use startService()
, but for post-7.0 devices, you have to use startForgroundService()
. Here is sample for code to start service.
해결책을 찾았습니다. Android 8.0 이전 버전에서는 startService()만 사용하면 되지만, 7.0 이후 버전에서는 startForegroundService()를 사용해야 합니다. 서비스를 시작하는 코드 샘플은 다음과 같습니다.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(new Intent(context, ServedService.class));
} else {
context.startService(new Intent(context, ServedService.class));
}
And in service class, please add the code below for notification:
그리고 서비스 클래스에서는 다음과 같은 코드를 알림(notification)에 추가해주세요.
@Override
public void onCreate() {
super.onCreate();
startForeground(1,new Notification());
}
Where O is Android version 26.
여기서 O는 안드로이드 버전 26을 의미합니다.
If you don't want your service to run in Foreground and want it to run in background instead, post Android O you must bind the service to a connection like below:
만약 Foreground에서 Service를 실행시키지 않고 Background에서 실행시키길 원한다면, Android O 이상에서는 다음과 같이 Service를 연결(bind)해야 합니다.
Intent serviceIntent = new Intent(context, ServedService.class);
context.startService(serviceIntent);
context.bindService(serviceIntent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//retrieve an instance of the service here from the IBinder returned
//from the onBind method to communicate with
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, Context.BIND_AUTO_CREATE);
가장 최근 달린 Solution
Alternate solution by using JobScheduler, it can start service in background in regular interval of time.
JobScheduler를 사용한 대안 솔루션으로, 일정한 시간 간격으로 백그라운드에서 서비스를 시작할 수 있습니다.
Firstly make class named as Util.java
먼저 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());
}
}
Then, make JobService class named as TestJobService.java
그런 다음 TestJobService.java라는 JobService 클래스를 만드세요.
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;
}
}
After that BroadCast Receiver class named ServiceReceiver.java
그 후에 ServiceReceiver.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);
}
}
Update Manifest file with service and receiver class code
Manifest 파일에서 서비스와 리시버 클래스 코드를 업데이트하세요.
<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>
Left main_intent launcher to mainActivity.java file which is created by default, and changes in MainActivity.java file are
기본적으로 생성된 MainActivity.java 파일에는 main\_intent launcher를 남겨두고, 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!! Background Service starts without Foreground service
와우!! 포그라운드 서비스 없이 백그라운드 서비스가 시작됩니다!
[Edit]: You can use Work Manager for any type of background tasks in Android.
[편집]: 안드로이드에서는 모든 종류의 백그라운드 작업에 Work Manager를 사용할 수 있습니다.
출처 : https://stackoverflow.com/questions/46445265/android-8-0-java-lang-illegalstateexception-not-allowed-to-start-service-inten
'개발 > 안드로이드' 카테고리의 다른 글
안드로이드에서 인텐트를 통해 구글 맵스 경로 안내 시작하기 (0) | 2022.12.19 |
---|---|
사용자가 선택하기 전에 Spinner에서 onItemSelected가 실행되지 않게 하는 방법 (0) | 2022.12.19 |
안드로이드 웹뷰의 캐시 완전히 지우기 (0) | 2022.12.19 |
Android에서 문자열을 Uri로 바꾸기 (0) | 2022.12.18 |
버튼 클릭 시 새로운 액티비티 시작하기 (0) | 2022.12.18 |