-
화면 회전하면 Fragment가 두 번 호출되는 문제카테고리 없음 2020. 11. 11. 21:06
상황:
Activity에 Fragment를 붙여놓고 Activity가 생성되면 자동으로 Fragment가 생성되도록 해놨다. 무슨 말인지 이해가 안 되면 조금 내려서 나오는 첫 번째 코드를 참고하자.
문제:
화면을 회전시키면 액티비티가 Destroy되었다가 다시 생성된다. 액티비티, 화면, 회전, 생명주기(activity, screen, rotation, lifecycle)의 키워드로 검색하면 많이 나올테니 자세한 설명은 생략한다.
여기까지는 좋은데, 한 번 회전시킬 때마다 Fragment가 두 번씩 생성되는 문제가 생겼다.
아래와 같은 코드로 로그를 찍어 확인해보았다.
액티비티 코드:
class MainActivity : AppCompatActivity() { private val TAG = "ActivityLog" override fun onCreate(savedInstanceState: Bundle?) { Log.d(TAG, "onCreate()") super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 프래그먼트 생성 val exFragment = ExFragment.newInstance() // 프래그먼트 붙임 supportFragmentManager.beginTransaction() .replace(R.id.csl_fragment, exFragment) .commit() } override fun onDestroy() { Log.d(TAG, "onDestroy()") super.onDestroy() } }
프래그먼트 코드:
class ExFragment : Fragment() { private val TAG = "FragmentLog" override fun onCreate(savedInstanceState: Bundle?) { Log.d(TAG, "onCreate()") super.onCreate(savedInstanceState) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.fragment_ex, container, false) } companion object { @JvmStatic fun newInstance() = ExFragment() } }
로그 화면:
첫 생성 때는 Fragment도 정상적으로 한 번만 생성되나, 화면 회전 이후에는 두 번씩 생성되는 것을 볼 수 있다.
필자가 만드는 앱의 경우에는 두 번씩 생성해도 기능에는 문제가 없었다. 그렇지만 나중에 사소한 문제가 눈덩이처럼 불어나서 뒤통수를 칠 것이 염려되어, 구글링을 해보았다.
마침 인터넷 세상에는 이와 같은 문제를 이미 겪은 사람이 있어 해결 방법이 나와있었다. 아래는 해결 방법이 나와있는 링크이다.
채택된 답변을 대충 요약하자면, 이미 첫 번째 생성할 때 프래그먼트가 하나 있는 상태인데, 화면을 회전해서 액티비티가 다시 onCreate되면 기존에 만든 Fragment와 새로 생성되는 Fragment 두 개가 생긴다는 뜻이다... (완벽하게 무슨 일이 일어나는지는 잘 모르겠다.)
아마 이미 만들어 둔 Fragment가 있는데, Activity의 onCreate()가 다시 호출되면서 아래 코드 부분이 다시 실행되어 프래그먼트를 또 만들어 붙이려 하기 때문에 일어나는 일인 것 같다.
// 프래그먼트 생성 val exFragment = ExFragment.newInstance() // 프래그먼트 붙임 supportFragmentManager.beginTransaction() .replace(R.id.csl_fragment, exFragment) .commit()
추측이 맞나 확인해보기 위해 Fragment의 onDestroy와 onDetach도 로그에 찍어보았다.
갈색 상자 부분이 맨 처음에 만들어진 Fragment이고, 회전 후 Activity가 다시 onCreate될 때, 파란색 상자로 표시된 Fragment가 생성되고, 새로 생긴 Fragment로 replace되어서 기존의 Fragment가 떨어져 나가고 소멸되었다고 하면 대충 이해가 되기도 한다. (어디까지나 추측이라 확실히 이렇다고는 말을 못 하겠다.)
추측이 맞다면 그냥 둬도 크게 문제가 되지는 않겠지만, 사소하게 앱의 성능을 갉아먹는 요인이 될 것 같으므로 해결하는 것이 좋아보인다.
해결 방법은 위 링크의 채택된 답변을 그대로 복붙해서 사용하면 된다. (채택된 답변은 질문이 끝나고 바로 나오는 답변으로, 추천 수 밑에 초록색 체크 표시가 되어있다.)
답변의 코드에 생략된 부분이 있어 초보자에게는 혼란의 여지가 있고, 더 간결히 정리할 수 있는 것 같아 조금 다듬어보았다.
class MainActivity : AppCompatActivity() { // 첫 번째 코드와 동일. 생략 // 프래그먼트 생성 val exFragment: ExFragment = supportFragmentManager.findFragmentById(R.id.csl_fragment) as ExFragment? ?: ExFragment.newInstance() // 첫 번째 코드와 동일. 생략 } // 첫 번째 코드와 동일. 생략 }
supportFragmentManager.findFragmentById 부분에서 기존에 만들어 둔 프래그먼트가 있으면 가져오고, 없으면 null을 반환하는 대신 Fragment를 새로 생성한다. (답변 링크에서는 findFragmentByTag를 사용했는데, 필자의 경우는 findFragmentById를 사용했다. 둘 다 기능은 비슷하다. 무엇을 사용할지는 fragment를 replace 또는 add 할 때 tag를 이용했는지, R.id.~~~의 형태로 id를 이용했는지에 따라 달라진다.)
아래는 정상 작동하는 로그이다. 화면 회전 한 번에 Fragment가 한 번만 onCreate된다.
끝!