72일차(2)/Android App(18) : Fragment (2), Fragment Lifecycle
step07fragment2
Myfragment
package com.example.step07fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
/*
[Fragment]
- 액티비티의 제어 하에 존재하는 미니 Controller
- 재활용을 염두에 두고 만드는 경우가 많다
- 재활용이라는 것은 여러개의 액티비티에서 활용된다는 의미
[ Fragment 만드는 방법 ]
1. Fragment 클래스를 상속받는다.
2. Fragment 의 layout xml 문서를 만든다.
3. onCreateView() 메소드를 오버라이딩 한다.
*/
public class MyFragment extends Fragment implements View.OnClickListener {
//필드
TextView textView;
int count=0;
// layout 으로 사용할 View를 만들어서 리턴해주어야 한다.
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//1. fragment_my.xml 문서를 전개해서 View를 만든 다음
View view=inflater.inflate(R.layout.fragment_my, container, false);
//만든 View에서 TextView의 참조값을 알아낸다.
textView=view.findViewById(R.id.textView);
textView.setOnClickListener(this);
//2. 해당 View 를 리턴해 준다.
return view;
}
@Override
public void onClick(View v) {
//카운트 값을 1 증가시키고
count++;
//정수를 문자열로 만들어서 TextView에 출력하기
textView.setText(Integer.toString(count));
/*
만일 count 값이 10의 배수이면 이 fragment를 제어하고 있는 액티비티에 해당 정보를 알려주기!
- 액티비티의 특정 메소드를 호출하면서 문자열 전달하기
- 단 특정 액티비티의 의존성은 없어야 된다.
*/
//이 fragment 를 제어하고 있는 액티비티의 참조값 알아내기.
FragmentActivity fa = getActivity();
//혹시 액티비티가 MyFragmentListener 인터페이스를 구현하지않았을 수도 있기 때문에 type을 확인해서 캐스팅한다.
if(count%10==0 && fa instanceof MyFragmentListener){
MyFragmentListener ma=(MyFragmentListener)fa;
ma.sendMsg(count+" 입니다!");
}
}
//액티비티에서 특정시점에 호출할 예정인 메소드
public void reset(){
count=0;
textView.setText("0");
}
//이 fragment 에서 전달하는 메세지를 받을 액티비티에서 구현할 인터페이스를 클래스 안에 정의하기
public interface MyFragmentListener{
public void sendMsg(String msg);
}
}
- layout으로 사용할 view를 리턴해주는 것이 제일 중요하다!
- 이 부분 수정하기! , false 인자를 추가해준다.
- 부모 뷰가 준비되지 않았을 때에는 에러가 날 수 있으므로 false를 옵션으로 전달해야 한다.
- 이 fragment를 나중에 부모 뷰가 다 준비되면 붙이겠다는 뜻
- inflater 객체를 사용해서 레이아웃, 전달된 뷰 그룹, false까지 전달해서 레이아웃을 전개하는 것이라고 생각하면 된다.
- onCreateView 에서 리턴된 View 가 레이아웃의 이 위치에 들어온다.
- 리턴한 View는 1개인데, 프래그먼트 객체 2개를 생성해서 똑같은 뷰가 2개 들어간 것!
activity_main.xml을 복붙해서 생성
activity_main2.xml 수정 (FragmentContainerView 사용)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
tools:context=".MainActivity"
android:orientation="vertical">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment1"
android:name="com.example.step07fragment.MyFragment"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_margin="10dp"/>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment2"
android:name="com.example.step07fragment.MyFragment"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_margin="10dp"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="resetFragment"
android:text="리셋"
android:id="@+id/Btn"/>
</LinearLayout>
- 프래그먼트 요소를 레이아웃 구성할 때 직접 작성했는데
최근에 Android Studio가 업데이트되면서 모양을 좀 바꿔두었다.
- fragment 요소를 View로 둘러싸서 넣는 방법이 있다.
- FragmentContainerView 를 사용한다.
- 디자인탭에도 이렇게 있다. 끌어다 놓으면 된다!
- 이 FragmentContainerView에 어떤 프래그먼트를 사용할 것이냐고 나온다. MyFragment 선택.
- 코드에 보면 이 요소가 자동으로 들어와있다
- 프래그먼트를 내부적으로 가지고 사용하는 view 라고 생각하면 된다. 사용법은 fragment와 거의 같다.
- 새 요소를 만들어주고 id를 이쪽에 부여한다.
- 원하는 프래그먼트를 집어넣을 때 FragmentContainerView 를 사용해서 집어넣으라는 뜻이다.
그냥 fragment 요소 대신!
- 이것도 view이므로 이렇게 참조값을 얻어올 수 있다.
- 위 코드(분홍)는 프래그먼트의 id를 사용해서 참조값을 찾아온 것이다.
(똑같은 아이디를 사용한다. 단 프래그먼트는 FragmentManager 사용)
- 아래(파랑)는 View의 참조값을 얻어온 것이다.
- FragmentContainerView 는 프레임 레이아웃을 상속받아서 만든 일종의 View이다.
새 모듈 생성-Empty Activity
step07fragment2
- 있는 fragment 양식으로 만들어보기
BlankFragment
package com.example.step07fragment2;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
public class BlankFragment extends Fragment {
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
//생성자
public BlankFragment() {
}
//자신의 객체(Fragment) 를 생성해서 리턴해주는 static 메소드
public static BlankFragment newInstance(String param1, String param2) {
//객체 생성
BlankFragment fragment = new BlankFragment();
//생성된 객체에 인자를 전달할 꾸러미(Bundle) 객체 생성
Bundle args = new Bundle();
//꾸러미 객체에 전달할 값을 담고
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
//꾸러미 객체를 Fragment 객체에 인자로 전달한 다음
fragment.setArguments(args);
//Fragment 객체를 리턴해준다.
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank, container, false);
}
}
- 객체 생성시 직접 new하지 말고 이 생성자를 호출해서 받아가라는 것이다. (static)
- 인자가 있으면 전달하고, 꾸러미 객체에 그 인자를 받아서 fragment 객체를 리턴하는 데에 활용.
- 이 fragment 객체의 참조값이 필요하다면 new 하는것이 아니라
생성자에 값을 전달해서 프래그먼트의 참조값을 얻어오도록 하기!
- 인자로 무엇을 전달할지, 전달할 값은 그때그때 다르지만
하지만 newInstance() 메소드를 사용할 것 !
- getArguments() 를 통해서 꾸러미 객체를 얻어낼 수 있다.
- set했던것을 아래에서 get으로 얻어와서 사용하는 것.
- 이 꾸러미에 담긴 데이터를 getString() 메소드로 읽어내기
- 저 args가 여기에 리턴된다고 보면 된다.
- 그러고 나서 아래의 onCreate 에서 View를 리턴해주면 된다.
- 이 fragment 구조가 안드로이드에 기본으로 만들어져있는 프래그먼트의 샘플이다!
- 이전에 공부한 Activity 생명주기의 많은 메소드와 비슷하게
프래그먼트도 고유한 생명주기를 가진다. 훨씬 더 많은 메소드가 있다.
- ctrl+o 하면 오버라이드할수있는 메소드들이 엄청나게나온다.
- on 해보면 많은 메소드가 있다.
- 여기서는 이 중 2가지 onCreate(), onCreateView() 를 override 한 것
** Fragment LifeCycle : 링크
- Fragment의 생명 주기!!
- 위의 2개를 주로 많이 override 한다.
- onCreate() : 준비 작업을 하는 메소드
- onCreateView() : 준비 작업단계에서 뷰를 만들어서 리턴하는 메소드
- onStop() : 마무리 작업을 할 게 있으면 여기서 하면 된다.
- 사실 지금 같은 fragment를 만드는 상태에서는 생명주기가 그렇제 중요하지는 않다.
- 하지만 이런 어플이라면? 스와이프하면 사진을 여러장 보여주는 어플이라고 하자.
- 이런 slider를 프래그먼트로 많이 만든다. 각각의 사진 하나하나가 fragment이다.
- 레이아웃은 같은데 안에 출력된 사진과 내용은 다른 구조이다!
- 사진을 좌우로 쭉 넘기다보면 쓸데없는 프래그먼트는 비활성화시킬 수 있도록 관리해야 한다.
- 저 프래그먼트에 어떤 내용/사진을 출력할 것인지, 각각의 프래그먼트 객체에 전달해주어야 한다.
- 그럴 때 newinstance() 메소드에서 데이터를 전달해주고,
onCreate() 에서 전달받은 값을 얻어내서,
onCreateView() 에서 출력할 준비를 하는 것이다.
'국비교육(22-23)' 카테고리의 다른 글
72일차(4)/Android App(20) : Custom View (0) | 2023.01.19 |
---|---|
72일차(3)/Android App(19) : View Binding (0) | 2023.01.19 |
72일차(1)/Android App(17) : Kotlin에서 java 클래스 사용, Lambda 표현식 (0) | 2023.01.18 |
71일차(2)/Android App(16) : Fragment(1) (1) | 2023.01.18 |
71일차(1)/Android App(15) : Kotlin Abstract Class, Companion, Map (0) | 2023.01.17 |