본문 바로가기
Android/Project

ViewPager2의 Fragment 데이터 받기 (Bundle 이용)

by YOONAYEON 2021. 8. 7.
Bundle 

 

Bundle(번들): key, value 쌍으로 데이터를 저장하는 일종의 Map 클래스

                 

 

 

Bundle과 Intent 차이

 

Bundle: 단순히 데이터 전달을 위한 직렬화 객체, 주로 Fragment간 데이터 전달에 사용

Intent: 특정 컴포넌트를 실행하고 원하는 데이터를 전달하기 위한, Activity간 또는 Activity-Fragment간에 사용

 

 

 

 

1. 일단 첫 번째 프래그먼트 클래스 내에 정적변수로 Bundle을 선언한다

: static변수는 프로그램 실행 시 할당되고 종료시 파괴되는 변수이기 때문에,

  프래그먼트가 여러번 실행되더라도 변수의 선언 및 초기화는 한번만 이루어짐 

public class Fragment1 extends Fragment{
	EditText et_name;
    static Bundle bundle;
}

 

2. Fragment액티비티에서 사용자에게 데이터를 받아온다.

 

    @Override
    public void onResume() {
        super.onResume();

        bundle = new Bundle(); //번들 생성
    }
   
    //프래그먼트 처음 시작하는 생명주기
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.setting_name, container, false);
       
        et_name = rootView.findViewById(R.id.et_name); //데이터 받기
        return rootView;
    }

 

3. 프래그먼트의 생명주기 중 하나인 onPause()을 상속해 bundle에 데이터를 넣는다.

 

    @Override
    public void onPause() {
        super.onPause();
        if(et_name.getText().toString().equals("")){
            //입력 필드가 공백일 때 작동 안함
        } else{
            bundle.putString("userName", et_name.getText().toString()); //bundle에 값넣기
        }
    }

 

4. 다른 프래그먼트에서 첫번째 프래그먼트의 번들을 받아온다.

public class Fragment2 extends Fragment {
    EditText et_home;
    Bundle bundle;

    @Override
    public void onResume() {
        super.onResume();
        
        //Fragment1의 Bundle 가져오기
        Fragment1 frag_1 = new Fragment1();
        bundle = frag_1.bundle;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.setting_home, container, false);
        et_home = rootView.findViewById(R.id.et_home);

        return rootView;
    }

    @Override
    public void onPause() {
        super.onPause();
        if(bundle != null){
            bundle.putString("userHome", et_home.getText().toString());  //번들에 데이터 추가
        }
    }
}

 

5. 이런식으로 사용자로부터 데이터를 받아올때마다 Fragment1의 bundle을 가져와서 데이터를 추가저장한다

 

 

6. 마지막 프래그먼트에서 오류 검증이나 DB작업을 해준다. 

: 또는 뷰페이저를 담은 액티비티의 onDstroy()생명주기를 이용하는 것도 가능

 

public class Fragment5 extends Fragment {
	EditText et_phone;
    Bundle bundle;
    
    @Override
    public void onResume() {
        super.onResume();

        //Bundle가져오기
        Fragment1 frag_1 = new Fragment1();
        bundle = frag_1.bundle;
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.setting_phone, container, false);

        et_phone = rootView.findViewById(R.id.et_phone);
        et_phone.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
        
        Button btn_done = rootView.findViewById(R.id.btn_done);
        btn_done.setOnClickListener(new Button.OnClickListener(){
                                        @Override
                                        public void onClick(View view) {
											//오류 검증
                                            if (bundle.getString("userName") == null || bundle.getString("userName").equals("")){
                                                StartActivity.fragmentChange(0);
                                                Toast.makeText(getActivity(), "이름을 입력해주세요!", Toast.LENGTH_SHORT).show();
                                            } else if{...}
                                            
                                            //DB작업
                                            
                                            getActivity().finish();
                                         }
         	);
         	return rootView;
         }

 

 

7. [참고] 프래그먼트의 데이터 오류검증을 위한 프래그먼트 이동 함수

 

  public class StartActivity extends FragmentActivity{
  
  	private static ViewPager2 mPager;
    private FragmentStateAdapter pagerAdaoter;
    
    //...
  
  	public static void fragmentChange(int index) {
    	    if (index == 0) {
        	    mPager.setCurrentItem(0);
        	}
       	 else if (index == 2){
        	    mPager.setCurrentItem(2);
        	} else if (index == 4){
           	 mPager.setCurrentItem(4);
        	}
    	}
  }

 

 

 

원래 Fragment간 통신 방법

 

나는 Bundle을 이용해서 내 방식대로 프래그먼트의 데이터를 받아왔지만, 원래  Fragment는 자신이 속한 activity와만 통신을 해야만 한다. 항상 자신이 속한 activity를 통해서 다른 fragment나 activity와 통신해야 한다는 말이다.

방법은 3가지 정도가 있다.

 

1. Bundle을 이용한 액티비티 전달
 : Fragment생성 후, 데이터를 넣은 Bundle을 전달할 수 있다.
  Fragment는 onActivityCreated메소드에서 번들을 받는다.

2. 메소드를 통해 Fragment의 메소드를 호출

3. Activity에서 리스터 이벤트 발생 : interface사용

 

참고로 프래그먼트는 Context클래스를 상속받지 않기 때문에 부모 액티비티를 얻기위해서 getActivity()를 사용

 

 

참고 링크

 

처음에는 프래그먼트의 onSaveInstanceState(Bundle outState) 에서 번들작업을 해주었는데, 액티비티가 종료될 때 여러 프래그먼트의 onSaveInstanceState 호출이 계속 뒤죽박죽이어서 번들에 제대로 데이터가 들어가지 않은 채 종료되었다.

생명주기를 계속 공부하다가 onStop에서 번들작업을 해주니 데이터가 제대로 들어가게 되었다.

 

 

프래그먼트의 사용에 관해:  https://webnautes.tistory.com/1089

 

안드로이드 개념 및 예제 - Fragment

Android 3.0(API 11)에서 Fragment가 처음 소개되었습니다. 재사용 가능한 유저 인터페이스를 생성하기 위한 새로운 컴포넌트라고 볼 수 있습니다. Fragment를 사용하면 코드를 재사용하여 동시에 여러

webnautes.tistory.com

 

프래그먼트와 액티비티의 생명주기: https://jinee0717.tistory.com/44

 

[Android] 안드로이드 Activity와 Fragment의 생명주기

Activity의 LifeCycle 안드로이드 앱은 여러개의 액티비티가 연결되어있는 구조라고 볼 수 있고, 각 액티비티는 생명주기에 따라 관리된다 액티비티의 클래스는 다음과 같이 6개의 콜백 함수를 제공

jinee0717.tistory.com

https://ddangeun.tistory.com/50

 

[안드로이드] Fragment 생명주기 ― Activity 생명주기와의 관계

Fragment Lifecycle 왼쪽은 Fragment의 Lifecycle, 프래그먼트 수명주기입니다. 생명 주기는 Android 작동 방식의 핵심으로, 생명 주기를 준수하지 않으면 메모리 누출 또는 애플리케이션의 비정상 종료가 발

ddangeun.tistory.com

 

'Android > Project' 카테고리의 다른 글

[Cafe In] 기록 #2: Retrofit2  (0) 2022.03.02
[Cafe In] 기록 #1  (0) 2022.02.17
Spinner & DatePicker 사용해 시간/날짜 입력받기  (0) 2021.08.05
ViewPager2 로 여러 개의 뷰 슬라이드 구현  (0) 2021.08.04
RecyclerView사용  (0) 2021.08.04