두 개의 프래그먼트
한 화면에 두 개의 프래그먼트가 들어가 있도록 만들려면 먼저 액티비티의 XML 레이아웃에 <fragment> 태그를 이용해 두 개의 프래그먼트를 넣어줍니다.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<fragment
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:name="org.techtown.fragment.ListFragment"
android:id="@+id/listFragment"
/>
<fragment
android:layout_width="match_parent"
android:layout_height="0dp "
android:layout_weight="1"
android:name="org.techtown.fragment.ViewerFragment"
android:id="@+id/viewerFragment"
/>
</LinearLayout>
이렇게 하면 화면의 위쪽에 하나의 프래그먼트, 아래쪽에 하나의 프래그먼트가 보이게 됩니다.
위쪽에 추가된 프래그먼트는 ListFragment라는 클래스를 가리키고 있으며 ListFragment라는 이름의 프래그먼트는 새로 정의합니다.
그 안에 리스트뷰가 들어가도록 말이죠.
아래쪽에 추가된 프래그먼트는 ViewerFragment 라는 클래스를 가리키고 있으며 이 프래그먼트도 새로 정의합니다.
그 안에는 이미지뷰가 들어가도록 합니다.
프래그먼트에서 액티비티의 메소드 호출
리스트뷰가 들어가 있는 프래그먼트에서 한 아이템을 선택하면 해당 아이템의 이미지를 이미지뷰가 들어가 있는 프래그먼트에 보여주어야 합니다.
그런데 하나의 프래그먼트에서 다른 프래그먼트로 직접 접근할 수 없으므로 시스템 역할을 하는 액티비티를 통해 명령이나 데이터를 전달해야 합니다.
프래그먼트는 메소드 호출 방식을 사용하게 되며 먼저 리스트 프래그먼트에서 액티비티의 메소드를 호출해야 합니다.
액티비티의 메소드를 호출할 때는 프래그먼트가 어떤 액티비티 위에 올라가더라도 프래그먼트의 소스가 변경되지 않도록 인터페이스를 정의하여 사용합니다.
ImageSelectionCallback 인터페이스를 정의했다면 이 인터페이스는 액티비티에서 구현하도록 하고 프래그먼트에서 이 인터페이스에서 정의한 메소드를 호출하도록 합니다.
public class ListFragment extends Fragment {
중략...
public static interface ImageSelectionCallback {
public void onImageSelected(int position);
}
public ImageSelectionCallback callback;
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof ImageSelectionCallback) {
callback = (ImageSelectionCallback) context;
}
}
프래그먼트는 액티비티 위에 올라갈 때 onAttach 메소드가 자동으로 호출되도록 만들어져 있으므로 onAttach 메소드가 호출되는 시점에 액티비티를 참조할 수 있습니다.
이 액티비티가 인터페이스를 구현하고 있다면 액티비티 객체를 변수에 할당합니다.
그리고 필요할 때 호출할 수 있습니다.
액티비티에서 프래그먼트의 메소드 호출
리스트 프래그먼트에서 액티비티의 메소드를 호출하면 액티비티에서는 이미지 프래그먼트의 메소드를 호출할 수 있습니다.
액티비티에 변수를 선언하고 프래그먼트 객체를 할당해두면 리스트 프래그먼트 객체나 이미지 프래그먼트 객체를 항상 참조할 수 있게 되며 액티비티의 메소드가 호출되었을 때 이미지 프래그먼트의 메소드를 호출함으로써 이미지를 변경할 수 있습니다.
public class MainActivity extends AppCompatActivity implements ListFragment.ImageSelectionCallback {
ListFragment listFragment;
ViewerFragment viewerFragment;
중략…
@Override
public void onImageSelected(int position) {
viewerFragment.setImage(images[position]);
}
}
액티비티에서 프래그먼트의 메소드를 호출할 때는 인터페이스를 사용할 필요가 없습니다.
생각해보기
- 액티비티에서 프래그먼트의 메소드를 호출할 때는 왜 인터페이스를 사용할 필요가 없는 걸까요?
- 프래그먼트 안에 프래그먼트를 추가했을 때 메소드 호출을 어떻게 하면 될까요?
참고 자료
comment
1. 프래그먼트는 자신이 사용'되'는 시점에서 어느 액티비티 위에 올라갈지 알 수 없기 때문에, 다양한 액티비티에서도 동작할 수 있도록 프래그먼트가 사용할 수 있는 공통의 인터페이스 메소드를 액티비티가 구현하게끔 강제해야합니다. 그러나 액티비티는 프래그먼트를 사용'하'는 시점에서 어느 프래그먼트를 사용할지 알 수 있습니다. 사용하는 프래그먼트를 알고 있다는 것은 프래그먼트가 가지고 있는 메소드는 어떤것들이 있는지 사용시점에 알고 있다는 것이고 따라서 프래그먼트가 공통의 인터페이스 메소드를 구현할 필요가 없습니다.
2. 액티비티 -> 부모 프래그먼트 -> 자식 프래그먼트 메소드순의 연쇄적 호출을 할것 같습니다.
⭐️ 생각해보기 ⭐️
1. 인터페이스는 추상화의 개념을 도입할 때 사용하는데 각 프래그먼트는 일반적으로 각각 독립적인 메소드를 사용하므로 필요가 없다고 생각합니다.
2. 액티비티에서 부모 프래그먼트 메소드 호출 - 부모 프로그먼트에서 자식 프로그래먼트 메소드 호출 순이 될 것 같습니다.
생각해보기
1. 음......솔직히 잘 모르겠습니다.... 시스템을 사용하지 않아서...?
2. root 프래그먼트에서 추가된 프래그먼트의 메소드를 호출하는 식으로 짜면 될 것 같습니다.