티스토리 뷰

Fragment는 말 그대로 액티비티 위에 놓일 수 있는 부분 레이아웃을 뜻하며, 새 액티비티를 생성할 때와 동일하게 새로운 xml 파일을 만들어 제작하지만 액티비티와는 다르게 실질적인 화면 전환 없이 부분적인 레이아웃만 변경하면 되므로 가볍게 화면 전환 효과를 낼 수 있어 쓰인다.

 

액티비티는 시스템이 직접 제어하지만, Fragment는 액티비티 위에서 Fragment Manager로 제어한다. 액티비티 위에서 동작하기 때문에 Fragment 사이에서의 데이터 이동은 intent나 다른 객체의 도움 없이도 단순히 메서드를 만들고 호출하는 방식으로 가능하다.

 

Fragment는 fragment xml layout 파일을 생성 후, 이를 제어할 FragmentClass.java를 생성하여 Fragment 클래스를 상속시켜 사용한다. 

 

Fragment 클래스가 가지고 있는 주요 메서드는 다음과 같다.

  • public final Activity  getActivity(): 이 프래그먼트를 포함하는 액티비티를 반환
  • public final FragmentManager getFragmentManager(): 이 프래그먼트를 포함하는 액티비티에서 프래그먼트 객체들과 소통하는 프래그먼트 매니저를 반환
  • public final Fragmetn getParentFragment(): 이 프래그먼트를 포함하는 부모가 프래그먼트일 경우, 리턴하며 액티비티일 경우 null을 리턴함
  • public final int getId(): 이 프래그먼트의 ID를 반환함

getFragmentManager()의 경우, FlagmentActivity.Class 내에 있는 getSupportFragmentManager() 로도 동일한 기능을 사용할 수 있다.

 

또한 액티비티 위에서 프래그먼트를 제어하기 위한 클래스인 FragmentManager가 가지고 있는 주요 메서드는 다음과 같다.

  • public abstract FragmentTransaction beginTransaction(): 프래그먼트를 변경하기 위한 트랜잭션을 시작
  • public abstract Fragment findFragmentById(int Id): ID를 이용한 프래그먼트 탐색
  • public abstract Fragment findFragmentByTag(String tag): Tag를 이용한 프래그먼트 탐색
  • public abstract boolean executePendingTransactions(): 트랜잭션은 commit() 메서드를 호출하여 실행되지만, 비동기 방식으로 실행되므로 즉시 실행하고 싶다면 이 메서드를 사용함

바로 코드와 한번 살펴보자.


▶ Main Fragment와 Menu Fragment를 사용하여 화면 전환하기

 

우선, mainFragment와 meneFragment를 다음과 같이 구성하고, activityMain.xml 레이아웃 파일에 mainFragment를 추가한다.

 

◎fragment_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                                   xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
                                                   android:layout_height="match_parent"
                                                   android:id="@+id/container"
>

    <Button
            android:text="메뉴 화면으로"
            android:layout_width="0dp"
            android:layout_height="wrap_content" android:id="@+id/button"
            app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" android:layout_marginTop="60dp"
            app:layout_constraintHorizontal_bias="0.0"/>
    <TextView
            android:text="메인 프래그먼트"
            android:layout_width="0dp"
            android:layout_height="37dp" android:id="@+id/textView"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toTopOf="@+id/button" app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

 

◎fragment_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                                   xmlns:app="http://schemas.android.com/apk/res-auto"
                                                   android:id="@+id/container"
                                                   android:layout_width="match_parent"
                                                   android:layout_height="match_parent" android:background="#ABD3F3">

    <Button
            android:text="메인화면으로"
            android:layout_width="0dp"
            android:layout_height="wrap_content" android:id="@+id/button2"
            app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" android:layout_marginTop="60dp"
            app:layout_constraintHorizontal_bias="0.0"/>
    <TextView
            android:text="메뉴 프래그먼트"
            android:layout_width="0dp"
            android:layout_height="37dp" android:id="@+id/textView"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toTopOf="@+id/button2" app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

◎activityMain.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity"
        android:id="@+id/container">
    <fragment
            android:layout_width="match_parent"
            android:layout_height="match_parent" android:name="com.example.fragmentex.MainFragment"
            android:id="@+id/mainFragment"/>
</androidx.constraintlayout.widget.ConstraintLayout>

이후 각 fragments java Class 파일을 생성하고, Fragment 클래스를 상속받아 onCreateView() 메서드를 재정의한다.

 

◎MenuFragment.java

package com.example.fragmentex;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

public class MenuFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_menu, container, false);
    }
}

onCreateView를 추가하면 위와 같이 inflater와 ViewGroup, Bundle을 인자로 받기 때문에 내부에서 inflate메서드를 호출하여 View를 제어할 수 있는 상태로 만들어준다.

 

MainFragment에서는 버튼을 클릭하면 MenuFragment로 화면을 변경해야하기 때문에 다음과 같이 MainFragment를 작성한다.

 

◎MainFragment.java

package com.example.fragmentex;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

public class MainFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_main, container, false);

        Button button = rootView.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MainActivity activity = (MainActivity) getActivity();
                activity.onFragmentChanged(0);
            }
        });
        return rootView;
    }
}

getActivity() 메서드를 사용하여 MainActivity 객체를 정의하고, MainActivity가 가지고 있는 onFragmentChanged() 메서드를 호출한다. 

 

◎MainActivity.java

package com.example.fragmentex;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    MainFragment mainFragment;
    MenuFragment menuFragment;

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

        mainFragment = (MainFragment) getSupportFragmentManager().findFragmentById(R.id.mainFragment);
        menuFragment = new MenuFragment();
    }

    public void onFragmentChanged(int index) {
        if(index == 0) {
            getSupportFragmentManager().beginTransaction().replace(R.id.container, menuFragment).commit();
        } else if(index == 1) {
            getSupportFragmentManager().beginTransaction().replace(R.id.container, mainFragment).commit();
        }
    }


}

위 코드는 getSupportFragmentManager() 를 사용하여 FragmentManager를 호출한 뒤, activity_main.xml에 정의한 mainFragment를 findFragmentById() 메서드로 가져왔다. 

 

이후에 onFragmentChanged() 메서드를 정의하여 프래그먼트를 변경하는 트랜잭션을 실행하도록 하였다.

 

작성한 코드를 실행하면 다음과 같이 버튼을 클릭했을 때, 화면이 전환되는 것을 확인할 수 있다.



프래그먼트도 액티비티와 마찬가지로 생명 주기가 존재하며, 생명 주기에 따른 메서드들을 정리하면 다음과 같다.

 

▶Fragment의 생명 주기 메서드

메서드 설명
onAttach(Activity) 프래그먼트가 액티비티와 연결될 때 호출
onCreate(Bundle) 프래그먼트가 초기화될 때 호출
onCreateView(LayoutInflator, ViewGroup, Bundle) 프래그먼트와 관련되는 뷰 계층을 만들어서 리턴
onActivityCreated(Bundle) 프래그먼트와 연결된 액티비티가  onCreate() 작업을 완료했을 때 호출
onStart() 프래그먼트와 연결된 액티비티가 onStart()되어 사용자에게 프래그먼트가 보일 때 호출
onResume() 프래그먼트와 연결된 액티비티가 onResume()되어 사용자와 상호작용할 수 있을 때
호출
onPause() 프래그먼트와 연결된 액티비티가 onPause()되어 사용자와 상호작용을 중지할 때 호출
onStop() 프래그먼트와 연결된 액티비티가 onStop() 됐을 때 호출
onDestroyView() 프래그먼트와 관련된 뷰 리소스를 해제할 수 있도록 호출
onDestroy() 프래그먼트의 상태를 마지막으로 정리할 수 있도록 호출
onDetach() 프래그먼트가 액티비티와 연결을 끊기 바로 전에 호출

Comments