Fragment는 Runtime에 단독으로 실행될 수 없으며, 반드시 Activity가 필요하다.
대표적인 configuration change인 스크린 회전은 Activity를 재생성하게 되고, 이때 개발자는 onSaveInstanceState()와 onRestoreInstanceState() 콜백을 오버라이드 하여, 뷰나 기타 상태등을 유지할 수 있게 된다.
물론 매니페스트에서 액티비티의 configurationChange옵션을 추가하여서 Activity가 재생성되지 않게 하는 방법 하나의 방법이 될 수 있다.
액티비티가 재생성 되면 액티비티에 속해 있던 프레그먼트는 어떻게 될까?
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if(savedInstanceState==null){ supportFragmentManager.beginTransaction() .replace(R.id.container, MyFragment.newInstance("Hello")) .commitNow() } }
보통 프레그먼트를 구현하거나 구글 샘플 예제를 확인해보면 이런식의 코드를 사용한다.
왜 savedInstanceState가 null인지 check할까?
Activity가 최초 생성 되었다면 savedInstanceState는 null이다.
Activity가 재생성되어 onCreate()가 다시 호출 되었다면 savedInstanceState는 null이 아니다.
그러면 여기서 궁금증이 하나 생긴다.
savedInstanceState의 null체크는 액티비티가 재생성 되었는지 체크할 수 있는 수단이 되는것이고, 재생성 되었을때는 프레그먼트를 화면에 보여주지 않는것인가?
아니다. 프레그먼트는 잘 나온다. 이상하다. 분명 액티비티는 재생성된것이고, 프레그먼트를 추가한적이 없는데, 프레그먼트가 화면에 나온다.
이유는 이렇다.
이미 생성되어 추가되었던 프레그먼트들은 configuration change에도 프레그먼트매니저에의해 살아남아 자동으로 관리가 된다.
그러므로 액티비티가 재생성되었을때 다시 프레그먼트를 add하거나 replace하지 않아도 화면에 표시되었던 것이다.
그렇다면 activity에 ViewPager를 구현한 경우는 어떻게 될까?
viewpager를 구현하기 위해서는 (FragmentStatePage)Adapter가 하나 필요하고, 페이지로 쓸 Fragment가 필요하다.
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Log.e(TAG,"onCreate") setContentView(R.layout.activity_main) pager.adapter = MyAdapter(supportFragmentManager) }
activity_main.xml
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <android.support.v4.view.ViewPager android:layout_width="0dp" android:id="@+id/pager" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:layout_height="0dp"/> </android.support.constraint.ConstraintLayout>
MyFragment.kt
class MyFragment : Fragment() { companion object { fun newInstance(s: String): MyFragment { return MyFragment().apply { arguments = Bundle().apply { putString("data", s) } } } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_main, container, false) view.text.text = arguments?.getString("data","default") return view } }
fragment_main.kt
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:id="@+id/text" android:gravity="center" android:autoSizeTextType="uniform" android:layout_height="match_parent" /> </android.support.constraint.ConstraintLayout>
MyAdapter.kt
class MyAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { override fun getItem(index: Int): MyFragment = MyFragment.newInstance(index.toString()) override fun getCount(): Int = 5 }
NOTE : 테스트를 위해 반드시 개발자 옵션에서 ‘활동 보관 안 함’ 옵션을 ON으로 하자. configuration 변화시 activity 또는 fragment 의 인스턴스를 강제로 재생성 한다.
페이지 화면에 보인다면 적당한 인덱스로 옮긴뒤 화면 회전(Screen Rotation)을 해보거나, 다른 앱을 왔다 갔다 이동을 하면서 페이지가 유지되는지 확인해보자.
ViewPager와 FragmentStatePagerAdapter도 똑같다. 우선 어댑터를 통해 프래그먼트를 매니저에 추가하면 화면 회전 뒤에도 getItem(int position)은 호출되지 않는다. 대신에 프레그먼트매니저 내부에서 프래그먼트의 기본생성자를 통해 프래그먼트를 재생성하며 이를 참조하게 된다.
0개의 댓글