[Flutter] detached() not working?

fanthasium·2023년 6월 27일
0

안드로이드 앱으로 디버깅중 얘를 스와이프로 강제 종료했는데 플러터에선 안드로이드의 라이프사이클을 인식 못하는 듯 보였다.

결론?

만약 스와이프를 통해 사용자가 강제 종료를 한다면 widget이 사라진 것으로 인식 되지 않아 flutter에선 deteched() 조차 하지 않음
그냥 Pause()로 안다.
그래서 우리가 할 것은 네이티브 앱과의 method Channel 이 있지만 결국 우리가 알고 싶은 것은 스와이프 강제종료시에deteched 를 감지하는 것이기에

방법 1:

 
  void dispose()  { 
  super.dispose();
  exit(0);
  }

을 해주거나

방법 2:

안드로이드 manifest에 service 선언

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

서비스 상속을 받아준다

open class MyService : Service() {

    override fun onBind(p0: Intent?): IBinder? {
        return null
    }

    override fun onTaskRemoved(rootIntent: Intent?) {

        //.. some code
        Log.e("asd","#!# Service TaskRemoved")
        stopSelf()
        super.onTaskRemoved(rootIntent)
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        return super.onStartCommand(intent, flags, startId)
    }

}

이후 onCreate에서 실행시키면 됨

class MainActivity: FlutterActivity() {

  private val CHANNEL = "user_main_body"


  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      startService(Intent(this,MyService::class.java))
  }
}

참고로 oncreate에 해야 해당 activity의 쓰레드가 종료될 때 서비스에게 종료를 알릴 수 있어 좀 더 안정적이라 한다

이건 flutter 의 고질적 문제기에 네이티브의 힘을 빌려야 했다.

아래 글은.. method 채널을 써야함을 알기까지 나의 과정을 통해 알게 된..라이프사이클 관리 함수다.. 필요하신 분은 보고..사용토록..ㅎ..하

🧐 WidgetsBindingObserver 상태관리

만약 필자와 같은 방식의 문제가아니라 widget이 지워졌을 때 상태관리라면 WidgetsBindingObserver 을 사용하도록 하자

class _LifecycleWatcherState 
extends State<LifecycleWatcher> 
with WidgetsBindingObserver {}

너무 길어져서 코드를 분리했는데
우리가 사용할 방법은
WidgetsBindingObserver 라는 Mixin 함수를 사용할 것이다

이를 사용하기 위해선

  
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this); // (2)
  }

  
  void dispose() {
    WidgetsBinding.instance.removeObserver(this); // (3)
    super.dispose();
  }

widget 생성시 , 종료시에 추가 해제를 해주고

나머지는


void didChangeAppLifecycleState(AppLifecycleState state) {

  switch (state) {
    case AppLifecycleState.resumed:
    // 앱이 표시되고 사용자 입력에 응답합니다.
    // 주의! 최초 앱 실행때는 해당 이벤트가 발생하지 않습니다.
      print("asdasd resumed");
      break;
    case AppLifecycleState.inactive:
    // 앱이 비활성화 상태이고 사용자의 입력을 받지 않습니다.
    // ios에서는 포 그라운드 비활성 상태에서 실행되는 앱 또는 Flutter 호스트 뷰에 해당합니다.
    // 안드로이드에서는 화면 분할 앱, 전화 통화, PIP 앱, 시스템 대화 상자 또는 다른 창과 같은 다른 활동이 집중되면 앱이이 상태로 전환됩니다.
    // inactive가 발생되고 얼마후 pasued가 발생합니다.
      print("asdasd inactive");
      break;
    case AppLifecycleState.paused:
    // 앱이 현재 사용자에게 보이지 않고, 사용자의 입력을 받지 않으며, 백그라운드에서 동작 중입니다.
    // 안드로이드의 onPause()와 동일합니다.
    // 응용 프로그램이 이 상태에 있으면 엔진은 Window.onBeginFrame 및 Window.onDrawFrame 콜백을 호출하지 않습니다.
      print("asdasd paused");
      break;
    case AppLifecycleState.detached:
    // 응용 프로그램은 여전히 flutter 엔진에서 호스팅되지만 "호스트 View"에서 분리됩니다.
    // 앱이 이 상태에 있으면 엔진이 "View"없이 실행됩니다.
    // 엔진이 처음 초기화 될 때 "View" 연결 진행 중이거나 네비게이터 팝으로 인해 "View"가 파괴 된 후 일 수 있습니다.
      print("detached");
      break;
    case AppLifecycleState.hidden:
      //TODO: Handle this case.
}
}

이런 식으로 상태관리를 해준다

각각의 State

detached : 앱이 여전히 flutter 엔진에서 호스팅되지만 모든 호스트 view에서 분리됩니다.

inactive : 앱이 비활성 상태이며 사용자 입력을 수신하지 않습니다.

paused : 앱이 현재 사용자에게 표시되지 않고 사용자 입력에 응답하지 않고 백그라운드에서 실행 중입니다.

resumed : 앱이 표시 되고 사용자 입력에 응답합니다. 앱 최초 실행때는 해당 이벤트가 발생하지 않습니다.

앱을 백그라운드로 실행했을 경우 : inactive -> paused

백그라운드에서 앱을 활성화 했을 경우 : resumed

앱을 종료했을 경우 : inavctive -> paused -> detached
-> 이건 서비스 등록을 했다던가, 직접 종료(exit(0)) 를 선언했다던가

결국 나의 목적은.. 이루지 못했으나 WidgetsBindingObserver라는 것을 알게 됐다는 것에 의의를 두기로 하자..

profile
디그다 디그다 (끙챠끙챠)

0개의 댓글