심재철 2018. 7. 12. 12:01

액티비티는 시스템에서 관리하지만 프래그먼트는 액티비티위에 올라가있기때문에 훨씬 가볍게 화면전환 할 수 있다.


프래그먼트 간 통신


프래그먼트는 액티비티 위에서 동작한다. 하나의 액티비티 위에 여러개의 프래그먼트가 존재할때 프래그먼트 끼리 통신을 하고 싶을때는 무조건 액티비티를 거쳐서 통신해야 한다. 직접적으로 프래그먼트들끼리 통신이 불가능하다.


1.액티비티 -> 프래그먼트 통신

간단하다. 액티비티에서 프래그먼트의 참조를 findViewById를 통해서 얻은다음에, 그 프래그먼트의 public 메소드를 호출하면 된다.


2.프래그먼트 -> 액티비티 통신

약간 복잡하다. 마찬가지로, 프래그먼트에서 호스트 액티비티(프래그먼트가 올라가있는)의 메소드를 호출하면 된다. 근데, 프래그먼트 내부에 리스너 인터페이스를 정의해놓고, 호스트 액티비티에서 그 이너 리스너 인터페이스를 구현하게끔 한다. 이렇게 하는 이유는 프래그먼트라는것은 액티비티위에 올라가서 동작하는데, 액티비티마다 이벤트 처리 콜백 메소드의 이름이 다를 수 있기 떄문이다. 예를 들어 프래그먼트가 액티비티 A,B,C 3개에 올라가 있는데 액티비티A에서는 onClickA 액티비티B에서는 onClickB 액티비티C에서는 onClickC이런식으로 콜백메서드가 정의되어 있다고 해보자. 그럼, 프래그먼트에서는 각 액티비티에 어떤 이름의 액티비티가 정의되어 있는지 일일이 확인해서 때에 따라 다르게 동작해야 한다. 이렇게 하기 번거롭기 떄문에 프래그먼트 내부에 리스너 인터페이스를 정의하고 호스트 액티비티가 그 리너스 인터페이스를 구현하게 함으로써 콜백메소드의 이름을 동일하게 유지시키는것이다. 이렇게 하게 되면 프래그먼트 클래스는 변경하지 않아도 잘 동작한다.

또한, 프래그먼트가 올라갈 모든 액티비티에서 프래그먼트의 이벤트(ex.클릭)를 처리하는 이벤트 처리 콜백 메서드(onClick())의 이름이 동일해진다.


예를 들면 다음과 같다.


public class SubFragment extends Fragment{

FragmentListener fragmentListener;


public interface FragmentListener{

public void onButtonClick(int position,String text);

}

}

위의 프래그먼트에서는 프래그먼트 내부에 있는 버튼이 클릭 되었을때 액티비티에 오버라이딩 되어 있는 콜백 메서드인 onButtonClick()이 호출 된다. 즉 프래그먼트의 이벤트 처리를 호스트 액티비티에서 하고 있는 것이다. 이렇게 동작하기 위해서는 호스트 액티비티가 반드시 FragmentListener를 구현하는 클래스여야 한다. 그렇지 않으면 프래그먼트 내의 버튼이 눌려도 동작하지 않을것이다.


그렇게 하기 위해서는 프래그먼트에 호스트 액티비티의 참조를 넘겨줄때 이 액티비티가 프래그먼트의 이너 리스너 인터페이스를 구현하고 있는지 확인해야 하며, 구현하지 않았을 경우에 에러를 내야 한다.


프래그먼트에 액티비티의 참조를 넘기는 시점은 onAttach()이다. 이 프래그먼트 생명주기 콜백 메소드 내부는 다음과 같이


@Override

public void onAttach(Activity activity){

super.onAttach(activity);


try{

fragmentListener = (FragmentListener) activity;

} catch(ClassCastException e){

throw new ClassCastException(activity.toString() + "must implement FragmentListener");

}

}


구현 되어야 한다. 빨간색으로 표시된 액티비티를 형변환 하는 부분이 핵심이다. 만약에 호스트 액티비티가 프래그먼트 내부의 이너 리스너 인터페이스를 구현하는 클래스가 아니라면 저 부분에서 클래스 캐스트 예외가 발생하여 프래그먼트가 생성되지 않고 예외를 던질것이다. 즉, 프래그먼트에 붙일 액티비티가 프래그먼트의 이너 리스너 인터페이스를 구현하는 경우에만 그 프래그먼트가 그 액티비티에 연결될 수 있다.


결국 두번째 통신 방법도 프래그먼트에서 액티비티의 메소드를 호출함으로써 통신을 하는것인데, 다만 프래그먼트는 여러개의 액티비티에 연결될수 있기 때문에 액티비티에 있는 메소드 명을 프래그먼트에서 정의한 대로 통일시켜야 하기 떄문에 약간 더 복잡해졌을 뿐이다.


프래그먼트의 이벤트 처리 방식 2가지


첫번째. 호스트 액티비티의 xml에 <fragment/> 엘리먼트를 집어 넣을때 속성으로 android:onClick="콜백메소드명"으로 설정.

이렇게 하게 될 경우 액티비티가 프래그먼트보다 먼저 이벤트를 수신한다.


두번째.위에 나온것 처럼 액티비티에서 프래그먼트의 이너 리스너 인터페이스를 구현.

이렇게 하게 될 경우 프래그먼트가 이벤트를 액티비티보다 먼저 받게 된다.


프래그먼트 생명주기




링크

onAttach() : 프래그먼트가 액티비티에 연결될때 호출됨

onCreata() : 프래그먼트가 초기화 될때 호출됨 -> new 객체 생성 시점은 아니다.

onCreateView() : 프래그먼트를 인플레이트할때 여기서 해야 한다.

onActivityCreated() : 프래그먼트에 연결된 액티비티의 onCreate()가 완료되면 호출된다.

onStart() : 프래그먼트가 화면에 보이기 시작할때

onResume() : 프래그먼트가 사용자와 상호작용 할 수 있을때


액티비티의 onCreate() 프래그먼트의 onActivityCreate()가 호출되면 메모리에 액티비티,프래그먼트가 올라간다.

프래그먼트는 액티비티에 종속되기 때문에 액티비티에 우선 연결이 되어야 생성될수있다. 따라서, 프래그먼트를 자바 코드에서 new를 통해서 객체를 생성했다고 해서 바로 onCreate()가 호출되는게 아니라 onAttach()가 먼저 호출된 다음에 onCreate()가 호출되는것이다.



프래그먼트 백스택



링크