이번에 만들고 있는 안드로이드 어플이 FrameLayout을 이용한 하단탭과, 프래그먼트 안에 뷰페이저가 함께 있는 구조인데, 뷰페이저의 어댑터로 사용하던 FragmentPagerAdapter가 deprecated되어 대체 방법인 FragmentStateAdapter를 이용하여 만들어 보았다.
안드로이드 공식 문서
ViewPager2를 사용하여 탭으로 스와이프 뷰 만들기
안드로이드 공식 문서를 많이 참고했다.
하단탭 첫번째 프레그먼트 JAVA 코드
public class HomeFragment extends Fragment {
Fragment fragment1, fragment2;
final int NUM_PAGES = 2; // 뷰페이저 총 화면 수
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
fragment1 = new FeedFragment(); // 뷰페이저 화면 1
fragment2 = new ArtistFragment(); // 뷰페이저 화면 2
ViewPager2 viewPager2 = view.findViewById(R.id.viewPager2);
viewPager2.setAdapter(new viewPagerAdapter(this)); // 여기서 this로 뷰페이저가 포함되어 있는 현재 프래그먼트(HomeFragment)를 인수로 넣어준다.
viewPager2.setCurrentItem(0);
// 탭과 뷰페이저 연결
TabLayout tabLayout = view.findViewById(R.id.tabLayout);
TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout(탭 레이아웃), viewPager2(탭과 연결하려고하는 뷰페이저), new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
if(position == 0) {
// 첫번째 화면일 때
tab.setText("Feed");
} else {
// 두번째 화면일 때
tab.setText("Artist");
tabLayoutMediator.attach();
return view;
// 뷰페이저2 어댑터
private class viewPagerAdapter extends FragmentStateAdapter {
public viewPagerAdapter(Fragment fragment) {
super(fragment);
@NonNull
@Override
public Fragment createFragment(int position) {
if(position == 0) {
// 첫번째 화면일 때
return fragment1;
} else {
// 두번째 화면일 때
return fragment2;
@Override
public int getItemCount() {
return NUM_PAGES;
위 코드를 실행했더니, 하단탭 1번부터 4번까지 한번씩 누르고 다시 1번 탭으로 돌아왔을 때 오류가 나면서 앱이 꺼지는 것을 확인할 수 있었다.
java.lang.IllegalStateException: Fragment no longer exists
1번째 탭(HomeFragment) 프레그먼트가 삭제되어, 없어져서 생기는 오류였다. 이를 해결하기 위해, 하단탭이 바뀌어도 1번째 탭 프래그먼트가 삭제되지 않도록, 프레그먼트를 백스택에 저장해놓는 방법을 사용하였다.
메인액티비티 JAVA 코드
public class MainActivity extends AppCompatActivity {
Fragment fragment1, fragment2, fragment3, fragment4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragment1 = new FeedFragment();
fragment2 = new LiveFragment();
fragment3 = new AlarmFragment();
fragment4 = new MypageFragment();
// 처음은 fragment1 보이기
FragmentTransaction fT = getSupportFragmentManager().beginTransaction();
fT.replace(R.id.container, fragment1);
fT.addToBackStack(null); // 백스택에 추가를 해놔야, fragment 가 교체될 때 삭제되지 않음
fT.commit();
BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
switch (item.getItemId()) {
case R.id.home:
FragmentTransaction fT1 = getSupportFragmentManager().beginTransaction();
fT1.replace(R.id.container, fragment1);
fT1.addToBackStack(null); // 백스택에 추가를 해놔야, fragment 가 교체될 때 삭제되지 않음
fT1.commit();
return true;
case R.id.live:
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment2).commit();
return true;
case R.id.alarm:
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment3).commit();
return true;
case R.id.mypage:
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment4).commit();
return true;
return false;