마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

notification 문제로 인한 앱 튕김

0 추천
       if (Build.VERSION.SDK_INT >= 26) {
            String CHANNEL_ID = "default";
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                    "Channel human readable title",
                    NotificationManager.IMPORTANCE_DEFAULT);

            ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);

            Notification notification = new Notification.Builder(this, CHANNEL_ID)
                    .setContentTitle("알람시작")
                    .setContentText("알람음이 재생됩니다.")
                    .setSmallIcon(R.mipmap.ic_launcher)

                    .build();

            startForeground(1,notification);
            



        }
    }

알람앱에서 다음과같은 코드로 실행하면 정해놓은 시간이 될 경우 앱이 강제종료됩니다.

startForeground(1,notification); 에서 1을 0으로 바꾸면 정해놓은 시간이 될떄 알람이 조금 울리다 역시 강제 종료 되는 상황입니다. 안정적이게 앱이 작동하게 만들고 싶습니다 도와주세요. 

탐탐비 (190 포인트) 님이 2020년 11월 17일 질문
혹시나 해서 그러는데,
NotificationCompat
NotificationManagerCompat
를 대신 사용해 보세요.
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                        .setContentTitle("알람시작")
                        .setContentText("알람음이 재생됩니다.")
                        .setSmallIcon(R.mipmap.ic_launcher);


                NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
                notificationManager.notify(1, builder.build());
코드를 다음과 같이 수정하였는데 한번 알람이 종료되면 얼마있다 앱이 튕깁니다 문제가 있을까요?
오류에 대한 로그캣 입니다.
2020-11-18 23:53:19.122 14612-14612/com.example.choi E/om.example.cho: Unknown bits set in runtime_flags: 0x8000
2020-11-18 23:53:40.954 14612-14612/com.example.choi E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.choi, PID: 14612
    android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{921c4c7 u0 com.example.choi/.RingtonePlayingService}
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1945)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

2개의 답변

+1 추천

스택오버플로우에 해당 질문과 답이 올라와 있네요.

https://stackoverflow.com/questions/44425584/context-startforegroundservice-did-not-then-call-service-startforeground

Context.startForegroundService() did not then call Service.startForeground()

먼저 Oreo에서는 서비스 클래스 사용에 대한 변경이 있었구요.

The system allows apps to call Context.startForegroundService() even while the app is in the background. However, the app must call that service's startForeground() method within five seconds after the service is created.

시스템은 Context.startForegroundService()를 호출하도록 해주는데, 앱이 백그라운드에 있을 때도 가능하다. 하지만, 앱은 반드시 서비스가 생성된지 5초 안에 startForeground()를 호출해야만 한다.

 

그리고 알려진 버그가 있네요. https://issuetracker.google.com/issues/76112072

The bug still here in API 26 and 27 (27.0.3). Affected android versions is 8.0 and 8.1.

 

구글의 해당 버그에 대한 답변:

https://issuetracker.google.com/issues/76112072#comment56

 

그리고 이건 임시적인 해결책:

https://www.theandroiddeveloper.com/post/context-startforegroundservice-did-not-then-call-service-startforeground

해결책이란 해당 서비스는 foreground에서만 실행되도록 디자인 되었기 때문에, 서비스가 foreground인지 체크하는 플래그를 만들어서, foreground인 경우만 startForeground를 실행하면 된다고 합니다.

 

이 버그가 수정되었는지는 좀 더 서치해 보시길 바래요.

spark (227,470 포인트) 님이 2020년 11월 19일 답변
참고로 앱이 Foreground인지 체크하실 때  https://developer.android.com/guide/components/activities/process-lifecycle나
https://developer.android.com/reference/android/app/Application.ActivityLifecycleCallbacks를 체크해 보시기 바랍니다. 전 이 방법들이 더 낫다고 보이네요.
그리고 필요하시다면
public class ForegroundService extends Service
처럼 서비스가 포그라운드인지 체크하는 기능이 있는 서비스 클래스를 만드시면 코드가 좀 더 독립적인 될 것 같네요.
제가 초보라 그런지 답변을 하나씩 읽어봤는데 적용을 하질 못했습니다 그래서 결국 SDK를 API25로 다운그레이드 하는 방법으로 해결했습니다 ㅠㅠ 답변 감사합니다
안드로이드 버전과 관련해서 두가지 염두해 두셔야할 게 있습니다.
하나는 안드로이드 앱 버전업을 매년해 주어야 하기 때문에 낮은 버전은 갈수록 사용자가 줄어들게 됩니다. 이 말은 결국은 SDK25를 버리셔야 될 순간이 생각보다 일찍 올 수 있습니다.
두번째가 더 당장 문제인데, 뉴스 검색해보시면 내년에 안드로이드폰에 루트인증서에 대한 대대적인 업데이트가 있습니다. 이 인증서를 제공하는 회사에서 안드로이드 7.0 Nudget을 지원하지 않기로 결정했습니다. 인증서를 업데이트 하지 않은 앱들은 웹브라우징에 문제가 생길 것이고, 이런 폰들은 보안적인 이유로 앱지원도 중단해야 합니다.
따라서 결국은 내년이면 SDK26부터 지원을 하실 수 밖에 없기 때문에, 해결하신 방법은 무용지물이 될 가능성이 굉장히 높습니다. 이 점 참고하세요.
0 추천

앱이 포그라운드에 있는지 백그라운드에 있는지 체크하는  클래스를 만들어 봤습니다. 급조한거라 동작은 잘 하는 것 같은데 코드 수정 및 테스트가 더 필요할 듯 합니다.

// app build.gradle에 dependency 추가
implementation 'androidx.lifecycle:lifecycle-process:2.2.0'

public class ForegroundChecker implements LifecycleObserver {

    private boolean isInForeground = false;

    private ForegroundChecker() {
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onRunInBackground() {
        isInForeground = false;
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onRunInForeground() {
        isInForeground = true;
    }

    public boolean isInForeground() {
        return isInForeground;
    }

    public static ForegroundChecker getInstance() {
        return Singleton.INSTANCE;
    }

    private static class Singleton {
        private static ForegroundChecker INSTANCE = new ForegroundChecker();
    }
}


public class MyApp extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        initLifecycleObserver();
    }

    private void initLifecycleObserver() {
        ProcessLifecycleOwner.get().getLifecycle().addObserver(ForegroundChecker.getInstance());
    }
}



public class MainActivity extends AppCompatActivity {

    private ForegroundChecker foregroundChecker;

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

        foregroundChecker = ForegroundChecker.getInstance();
        //foregroundChecker.isInForeground() ? "Foreground" : "Background"
    }

}

참고로, 전 androidx만 쓰기 때문에 Androidx를 쓰지 않으시면 마이그레이션 하시길 권장드리며, 굳이 support library를 쓰셔야 한다면 https://developer.android.com/reference/android/arch/lifecycle/ProcessLifecycleOwner 에서 확인해 보시길 바랍니다. 참고로 ForegroundChecker는 inner static singleton을 사용하는 Singleton 클래스입니다. 

그리고 Service보다는 WorkManager를 권장하는 것 같습니다. 관심이 있으시면 이것도 살펴보시면 더 안정적인 앱을 만드시는게 도움이 될 듯 합니다.

https://developer.android.com/topic/libraries/architecture/workmanager

spark (227,470 포인트) 님이 2020년 11월 20일 답변
...