[안드로이드] deprecated 되지 않은 방법으로 프래그먼트 안에 뷰페이저 넣은 화면 만들기

박서현·2021년 6월 3일
0

안드로이드

목록 보기
2/9
post-thumbnail
post-custom-banner

이번에 만들고 있는 안드로이드 어플이 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;
        });
    }   	
}

하단탭이 있는 메인 액티비티에서 FrameLayout 상단에 보여질 화면을 교체할 때, addToBackStack(null);을 사용해서 프래그먼트가 교체될 때, 삭제되지 않고, 백스택에 저장되도록 설정하였다.

프래그먼트를 삭제 또는 교체하고 트랜잭션을 백 스택에 추가하면 삭제된 프래그먼트가 중지됩니다(폐기되지는 않음). 사용자가 뒤로 탐색하여 프래그먼트를 복원하는 경우 프래그먼트가 다시 시작됩니다. 트랜잭션을 백 스택에 추가하지 않으면 프래그먼트가 삭제되거나 교체될 때 폐기됩니다.

위는 안드로이드 공식 문서에 나와있는 설명이다. 아래 링크를 눌러 공식 문서를 확인하자.

유연한 UI 빌드

이렇게 프래그먼트까지 다시 설정하고나니, 원하는대로 하단탭과 뷰페이저가 잘 동작하는 것을 확인할 수 있었다.

profile
차곡차곡 쌓아가기
post-custom-banner

0개의 댓글