<프래그먼트의 수명주기>

프래그먼트는 액티비티 위에 올라가는 것이므로, 프래그먼트의 수명주기도 액티비티의 수명주기에 종속적이다.

그리고 여기에 프래그먼트만 가질 수 있는 독립적인 상태 정보들이 추가되었다.

 

<프래그먼트가 화면에 보이기 전에 호출되는 상태 메서드>

  • onAttach(Activity) : 프래그먼트가 액티비티와 연결될 때 호출됨. 프래그먼트에서 해당 액티비티를 참조하고 싶다면 onAttach 메서드로 전달되는 파라미터를 참조하거나 / getActivity 메서드를 호출하여 반환되는 객체를 참조할 수 있다.
  • onCreate(Bundle) : 프래그먼트가 초기화될 때 호출됨.
  • onCreateView(LayoutInflator, ViewGroup, Bundle) : 프래그먼트와 관련되는 뷰 계층을 만들어서 리턴함.

      프래그먼트와 연결된 액티비티의 상태에 영향을 받는 메서드

  • onActivityCreated(Bundle) : 프래그먼트와 연결된 액티비티가 onCreate 매서드의 작업을 완료했을 때 호출됨.
  • onStart() : 프래그먼트와 연결된 액티비티가 onStart되어 사용자에게 프래그먼트가 보일 때 호출됨.
  • onResume() : 프래그먼트와 연결된 액티비티가 onResume되어 사용자와 상호작용할 수 있을 때 호출됨.

 

<프래그먼트가 화면에서 보이지 않게 될 때(중지될 때) 호출되는 상태 메서드>

  • onPause() : 프래그먼트와 연결된 액티비티가 onPause되어 사용자와 상호작용을 중지할 때 호출됨.
  • onStop() : 프래그먼트와 연결된 액티비티가 onStop되어 화면에서 더 이상 보이지 않거나 / 프래그먼트의 기능이 중지되었을 때 호출됨.
  • onDestroyView() : 프래그먼트와 관련된 뷰 리소스를 해제할 수 있도록 호출됨.
  • onDestroy() : 프래그먼트의 상태를 마지막으로 정리할 수 있도록 호출됨.
  • onDetach() : 프래그먼트가 액티비티와 연결을 끊기 바로 전에 호출됨.

위에서 작성한 순서대로 실행된다.

 

주의할 점 : 프래그먼트 객체가 new 연산자로 만들어졌더라도, 액티비티 위에 올라가기 전까지는 프래그먼트로 동작하지 않는다.

 

<분할화면 만들기 - 한 화면에 2개의 프래그먼트 배치>

1. 프래그먼트를 두 개 생성한다. (ListFragment, ViewerFragment) 아래와 같이 XML을 배치한다.

fragment_list (왼) / fragment_viewer (오)

 

2. <ListFragment.java>

package com.example.chapter5_2;

public class ListFragment extends Fragment {

    public static interface ImageSelectionCallback{
        public void onImageSelected(int position);
    }
    public ImageSelectionCallback callback;

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        if(context instanceof ImageSelectionCallback){
            callback=(ImageSelectionCallback) context;
        }
    }

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

        Button button = rootView.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(callback!=null)
                    callback.onImageSelected(0);
            }
        });

        Button button2 = rootView.findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(callback!=null)
                    callback.onImageSelected(1);
            }
        });

        Button button3 = rootView.findViewById(R.id.button3);
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(callback!=null)
                    callback.onImageSelected(2);
            }
        });

        return rootView;
    }
}

 

2 - (1) ImageSelectionCallback

public static interface ImageSelectionCallback{
    public void onImageSelected(int position);
}
public ImageSelectionCallback callback;

보면 interface ImageSelectionCallback으로 되어있다. 액티비티마다 다른 이름의 메서드를 만들면 번거롭기 때문에 인터페이스를 정의한 후 액티비티가 이 인터페이스를 구현하도록 만든 것이다.

 

mainActivity에서 onImageSelected 메서드를 정의한 후, 그 메서드를 호출한다. (화면에서 선택된 버튼에 따라 다른 프래그먼트의 이미지를 바꿔주려면 액티비티 쪽으로 데이터를 전달해야하므로)

 

callback 변수의 자료형을 ImageSelectionCallback으로 선언함.

 

2 - (2) onAttach 재정의

@Override
public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    if(context instanceof ImageSelectionCallback){
        callback=(ImageSelectionCallback) context;
    }
}

onAttach 메서드 안에서는 MainActivity 객체를 참조한 후 ImageSelectionCallback 타입으로 된 callback 변수에 할당한다.

(뭐라는지 모르겠다만 암튼 그렇구나.)

 

2 - (3) 버튼 onClick 메서드

public void onClick(View view) {
    if(callback!=null)
    callback.onImageSelected(0);
}

callback이 null이 아니라면 onImageSelected 메서드를 실행한다. 버튼마다 다른 이미지를 보여주기 위해 각각 0, 1, 2의 값을 넣어준다.

 

3. <ViewerFragment.java>

package com.example.chapter5_2;

public class ViewerFragment extends Fragment {
    ImageView imageView;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_viewer, container, false);

        imageView = rootView.findViewById(R.id.imageView);
        return rootView;
    }
    
        public void setImage(int resId){
            imageView.setImageResource(resId);
    }
}

@Nullable이란 null을 허용한다는 의미다. (근데 저걸 굳이 이 코드에 추가해야하나? 없어도 상관없지 않나.. 모르겄다)

public void setImage(int resId){
    imageView.setImageResource(resId);
}

setImage 메서드를 통해 이미지를 viewerFragment에 세팅한다.

 

4. <activity_main.xml>

XML 코드를 수정한다. 최상위 태그를 LinearLayout으로 변경하고, fragment 태그를 2개 추가한다.

width=match_parent, height="0dp", weight="1"로 설정한 다음 각각 name과 id를 설정하면 디자인 화면에서 저렇게 나오는 것을 볼 수 있다.

 

5. <MainActivity.java>

(이 코드를 작성하기 전에, 처음에 이미지 파일 3개 letters, jibri, lunch를 drawable 폴더에 넣은 상태이다.)

package com.example.chapter5_2;

public class MainActivity extends AppCompatActivity implements ListFragment.ImageSelectionCallback {
    ListFragment listFragment;
    ViewerFragment viewerFragment;

    int[] images = {R.drawable.letters, R.drawable.jibri, R.drawable.lunch};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FragmentManager manager = getSupportFragmentManager();
        listFragment = (ListFragment) manager.findFragmentById(R.id.listFragment);
        viewerFragment = (ViewerFragment) manager.findFragmentById(R.id.viewerFragment);
    }

    @Override
    public void onImageSelected(int posistion){
        viewerFragment.setImage(images[posistion]);
    }
}

 

5 - (1) 배열로 이미지 설정.

int[] images = {R.drawable.letters, R.drawable.jibri, R.drawable.lunch};

각각 [0], [1], [2]의 위치에 있는 것을 알 수 있다. 이 위치를 이용해서 onImageSelected 메서드가 이미지를 세팅할 수 있게 하는 것.

 

5 - (2) onImageSelected 메서드

@Override
public void onImageSelected(int posistion){
   viewerFragment.setImage(images[posistion]);
}

 

순서를 정리하면 이렇다.

  1. ListFragment에서 첫번째 버튼을 누른다. callback.onImageSelected(0);가 실행된다.
  2. MainActivity에 정의되어있는 onImageSelected 메서드가 실행된다. 이 메서드 안에 있는viewerFragment.setImage(images[0]); 코드가 실행된다. (images[0] = R.drawable.letters)
  3. setImage 메서드 안에 있는 imageView.setImageResource(R.drawable.letters); 코드가 실행된다.
  4. letters 이미지가 ViewerFragment에 나타난다.

 

6. <실행 결과>

버튼을 누르면 이미지가 변경된다.