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

앱 강제 종료시 이벤트를 발생하려면 어떻게 해야할까요?

0 추천

여기서 말하는 강제종료는 기기마다 다르겠지만 안드로이드 기기 아래에 기본적으로 있는 세 버튼중 첫번째 버튼을 누르면 실행 앱이 작아지고 테두리 상태가 되며, 그 상태에서 위나 옆으로 슬라드하여 종료하는 경우를 말합니다.​

제가 Log를 보면서 위와 같은 강제종료 상황을 지켜보았는데 해당 Activity나 Fragment의 onDestroy메소드가 호출이 되는 경우도 있고 안되는 경우도 있고, 호출이되더라도 첫줄만 실행되고 끝납니다. ​

제가 원하는건 강제종료가 되어도 아래코드와 같이 onDestroy메소드가 호출이되면서 서비스를 종료하게 하는 것인데, 서비스가 정상적으로 종료가 안되니 제가 원하는 결과들이 나오지 않더군요 ㅜㅜ​

혹시 앱을 저렇게 강제종료할 시 onDestroy()가 아닌 호출되는 다른 함수가 있나요? 아니면 강제종료시 이벤트 처리를 할 수 있는 다른 방법은 없을까요? 답변 부탁드립니다 !​

(앱 강제종료시 서비스만 따로 종료하는 방법이 있으면 그것을 알려주셔도 감사하겠습니다!!)

@Override

public void onDestroy() {

super.onDestroy();

Log.i("HomeFragment", "onDestroy 로 들어옴");

Intent intent = new Intent(getActivity(), MyService.class);

getActivity().stopService(intent);

}

lns0mnia (380 포인트) 님이 2020년 12월 20일 질문

1개의 답변

+2 추천
 
채택된 답변
이 문제를 해결하는 전통적인 방법은 3가지가 있습니다. 근데 더 좋은 방법도 있네요. (마지막 참고)

1. 항상 데이터를 저장합니다. 평상시에 데이터를 SharedPreference나 파일 혹은 DB에 보관합니다.
SharedPreference에 gson으로 저장하면, 객체가 저장되고, 다시 불러올 수 있습니다.

2. Service를 다른 process로 실행하면, activity가 죽어도 해당 서비스는 살아 있습니다. 이 서비스가 데이터를 처리하고 죽으면 됩니다.

3. 죽지않는 Foreground Service로 실행을 하면, 앱이 죽지 않습니다. (제일 안좋은 방법)

 

*** 구글링하니, 더 좋은 방법이 있네요. 2번하고 비슷하지만, 정말 쉽게 수정이 가능하네요.

https://stackoverflow.com/questions/19568315/how-to-handle-code-when-app-is-killed-by-swiping-in-android

<service
    android:name="com.myapp.MyService"
    android:stopWithTask="false" />

오우, 완전 대박인데요. 채택된 답변이니까, 확실합니다.

그러나 근본적으로는 1번 방식을 권고합니다. 언제든지 시스템이 둘 다 죽일 수 있습니다.
Will Kim (43,170 포인트) 님이 2020년 12월 20일 답변
lns0mnia님이 2020년 12월 22일 채택됨
@spark
@Will Kim
두 분다 자세하고 좋은 답변들 정말 감사합니다ㅜㅜ 먼저 제가 구현하고자 하는 앱에서는 서버를 이용하지도 않고 회원정보 저장도 하지 않기 때문에 보안 문제는 우려가 안될 것으로 보입니다.
 제가 저장하고자 하는데이터는 서비스에서 핸들러로 구현된 스톱워치의 시간인데, MainActivity화면에서 다른 Activity로 화면이 넘어가도 계속 시간을 측정가능하게 해야합니다.  따라서 onStop이나 onPause에서 서비스를 해제하면 화면이 바뀔때 이 함수들이 호출이되므로 서비스가 정지되기때문에 onDestroy에 서비스 해제 코드를 구현 했던 것입니다.
그리고 제가 서비스 class안에는 onStartCommand에서 저장된 SharedPreference를 불러오고 onDestroy에서 SharedPreference를 이용한 시간 데이터를 저장하도록 하였습니다. 이렇게 하였는데도 강제종료시 Activity의 onDestory함수가 호출이 잘 되지 않아서 서비스가 정상 종료가 되지 않게 되고,  다시 앱을 실행해보면 저장된 객체가 마지막으로 안전하게 종료된 시점의  객체로 저장되어있습니다.
 즉, 앱을 종료했다 다시 켜도 종료하기 전의 측정된 시간이 그대로 남아있어야 하는 부분인데 이것이 정상종료가 되면 SharedPreference로 저장이 되는데, 강제종료가 되면 저장이 안되는 상황입니다. 답변으로 말씀해주신 onTaskRemove함수를 호출하는 방법은 4초이상이 걸리는 것 같아서 안되는 거 같고, SharedPreference는 제가 서비스 class안에 구현을 했지만 강제종료시 호출이 안되기때문에 계속 해결방법을 찾고있네요 ㅜㅜㅜㅜ  정말 좋은 답변 감사합니다.
그럼, 서비스는 onStop에서 종료하시지 마시고 대신 BraodCastReceiver나 binder를 이용해서 서비스로 부터 이벤트를 받아서 데이터를 저장해 보시죠. 액티비티에서는 onStart/onStop에 BroadCastReciver를 등록/해제해주면 될 것 같구요.
스톱워치의 시간을 매번 SharedPreference에 저장하면,
앱이 정지되었을 마지막 시간이 저장되는 거 아닌가요?
서비스의  Handler에서 1초 마다 호출되게 만들어서 남은 시간이나, 진행된 시간을 계속 저장하면, 언제 죽어도, 마지막 부분을 가져올 수 있죠.
종료된 시점을 정확하게 저장할 수 없다면, 중간중간 저장해서,
언제 죽더라도 1초던, 100ms 던, 최종 값을 계속 보관하면 문제가 해결 될 것 같네요.
예전에 자전거 앱을 만들어 계속 위치를 보관하게 했습니다.
앱이 중간에 죽을 수도 있기 때문에, 주기적으로 배열을 gson으로 저장했습니다. 많게는 1메가가 넘는 파일이지만, 앱이 강제로 죽더라도 최소한 1분 이상 저장데이터를 손해보지 않게 만든 거죠.
스톱 워치라면 저장할 내용이 많지 앟을테니, 100ms던 1초마다 저장해도 될 것 같네요.
이 방법과 onDestroy에서 저장하는 것을 두개 다 동시에 쓸 수 있죠.
@spark
BroadCastReceiver를 아직 사용해본적이 없어서 관련하여 좀더 공부해보고 이방법으로도 꼭 시도해봐야겠습니다. 정말 좋은 답변들 감사합니다!!!!
@Will Kim
진짜 감사합니다!ㅜㅜ 일단 이방법으로 해결을 했습니다!! Will Kim님 말씀대로 Handler내에서 SharedPreference를 사용하여 저장을 하면 정해진 시간마다 저장을 계속 할 수 있었네요..!!
아직도 공부할 부분들이 많은거 같습니다. 정말 큰 도움 되었습니다. 감사합니다~~!!!
...