• 로그인 함 해보끄나?

  • Sarangnamu.net June 17, 2003
    Home Login Profile Study Open Project Q&A Google Code
    OnBackPressedDispatcher 이용
    Last Modify : 05 September, 2019(08:16)
    기존에 Fragment 에서 h/w back key 를 이용하기 위해 OnBackPressedListener 를 생성 한 뒤 
     
    interface OnBackPressedListener {
        fun onBackPressed(): Boolean
    }
     
    activity 에는 아래와 같이 설정 하고 
     
    override fun onBackPressed() {
        // 현재 fragment 가 OnBackPressedListener 를 상속 받고 return true 를 하면 인터페이스에서
        // h/w backkey 를 처리한 것으로 본다.
        val fragment = supportFragmentManager.current
        if (fragment != null && fragment is OnBackPressedListener && fragment.onBackPressed()) {
            return
        }
     
        if (mBackPressed.onBackPressed()) {
            super.onBackPressed()
        }
    }
     
    Fragment 에는 OnBackPressedListener 상속해서 내부적인 이벤트가 존재하면 onBackPressed 에서 true 를 반환해서 처리하고 그게 아니면 activity 에서 처리하도록 false 를 전달했는데 
     
    override fun onBackPressed(): Boolean {
        if (mIssueViewModel.viewRealtimeIssue.isVisible()) {
            toggleIssueLayout() 
     
            return true // 내부에서 back key를 처리 함 
        }
     
        return false // activity 에서 back key 를 처리하도록 false 전달 
    }
     
    새롭게 나온 OnBackPressedDispatcher 를 이용하려면 어떻게 해야하나?  기존의 인터페이스를 어떻게 살릴까 하고 잠시 뒤적여 본 결과 Activity 에서는 아래와 같이 설정하고 
     
    override fun onBackPressed() {
        if (!onBackPressedDispatcher.hasEnabledCallbacks()) {
            mBackPressed.onBackPressed()
            return
        }
     
        super.onBackPressed()
    }
     
    Fragment 의 Base Class 에서 아래와 같이 설정하는 식으로 했더니만 기존의 방식을 이용하면서 신규 방식도 적용되도록 코드를 완성 시켰다. 
     
    private var mOnBackPressedCallback: OnBackPressedCallback? = null
     
    private fun initBackPressedDispatcher() {
        if (this is OnBackPressedListener) {
            mOnBackPressedCallback = object: OnBackPressedCallback(false) {
                override fun handleOnBackPressed() {
                    mOnBackPressedCallback?.isEnabled = !onBackPressed()
                }
            }
     
            mOnBackPressedCallback?.let {
                requireActivity().onBackPressedDispatcher.addCallback(this@BaseFragment, it)
            }
        }
    }
     
     
    다만 다른점은 이전에는 onBackPressed 를 처음 전달 받기 위해서는 mOnBackPressedCallback?.isEnabled 값을 true 로 지정해야 한다는 점이 다르다. +_ + 그게 좀 귀찮긴 하지만 어쨋든 변화에 적응은 해야 되니 후...
     
    protected fun backPressedCallback(enableCallback: Boolean = true) {
        mOnBackPressedCallback?.isEnabled = enableCallback
    }
     
    암튼 그렇고 좀 더 깊게 보자면 새로운 Back Pressed Callback 은 androidx.activity.ComponentActivity 에 구현되어 있는데 
    주요 코드는 아래와 같다. 
     
    private final OnBackPressedDispatcher mOnBackPressedDispatcher =
            new OnBackPressedDispatcher(new Runnable() {
                @Override
                public void run() {
                    ComponentActivity.super.onBackPressed();
                }
            });
     
    @Override
    @MainThread
    public void onBackPressed() {
        mOnBackPressedDispatcher.onBackPressed();
    }
     
    @NonNull
    @Override
    public final OnBackPressedDispatcher getOnBackPressedDispatcher() {
        return mOnBackPressedDispatcher;
    }
     
    보통 사용하는 AppCompatActivity 의 상속 순서는 FragmentActivity -> ComponentActivity 순 
    이며 H/W 키에 의해 onBackPressed() 가 호출 되는데 onBackPressed 의 내부 코드를 보면 아래의 형태를 가진다. 
     
    mOnBackPressedDispatcher.onBackPressed(); 
     
    즉  OnBackPressedDispatcher 에 등록되어 있는 Callback 을 호출하는 형태인데 callback 에 enabled 값을 참조하여 
     
    @MainThread
    public void onBackPressed() {
        Iterator iterator =
                mOnBackPressedCallbacks.descendingIterator();
        while (iterator.hasNext()) {
            OnBackPressedCallback callback = iterator.next();
            if (callback.isEnabled()) {
                callback.handleOnBackPressed();
                return;
            }
        }
        if (mFallbackOnBackPressed != null) {
            mFallbackOnBackPressed.run();
        }
    }
     
    콜백을 받을지 말지를 정의 할 수 있다. 
    등록되어 있는 모든 콜백의 enabled 값이 false 면 OnBackPressedDispatcher 초기화 코드인 mFallbackOnBackPressed 를 실행하게 된다. 
    이후 ComponentActivity 의 하위?(부모) 클래스의 onBackPressed 를 호출하게 된다.
     
    끝.
     
    ps. 근데 구글아... 이거 좀 -_ - 설계 잘못된거 같은데...

     

    Comment


    입력하3 1591025094



    Locations of visitors to this page