수색…


소개

단편 및 상호 통신 메커니즘 소개

통사론

  • void onActivityCreated (Bundle savedInstanceState) // 프래그먼트의 활동이 생성되고이 프래그먼트의 뷰 계층 구조가 인스턴스화 될 때 호출됩니다.

  • void onActivityResult (int requestCode, int resultCode, Intent data) // startActivityForResult (Intent, int)에 대한 이전 호출의 결과를 수신합니다.

  • void onAttach (Activity activity) //이 메소드는 API 레벨 23에서 더 이상 사용되지 않습니다. 대신 onAttach (Context)를 사용하십시오.

  • void onAttach (Context context) // 프래그먼트가 컨텍스트에 처음 첨부 될 때 호출됩니다.

  • void onAttachFragment (Fragment childFragment) // 단편이이 단편의 하위로 첨부 될 때 호출됩니다.

  • void onConfigurationChanged (Configuration newConfig) // 구성 요소가 실행되는 동안 장치 구성이 변경되면 시스템에서 호출합니다.

  • void onCreate (Bundle savedInstanceState) // 조각의 초기 생성을 호출합니다.

  • View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) // 조각이 사용자 인터페이스보기를 인스턴스화하도록 호출되었습니다.

  • void onDestroy () // 조각이 더 이상 사용되지 않을 때 호출됩니다.

  • void onDestroyView () onCreateView (LayoutInflater, ViewGroup, Bundle)에 의해 이전에 생성 된 뷰가 프래그먼트에서 분리되었을 때 호출됩니다.

  • void onDetach () // 프래그먼트가 더 이상 액티비티에 연결되어 있지 않을 때 호출됩니다.

  • void onInflate (Activity activity, AttributeSet attrs, Bundle savedInstanceState) //이 메소드는 API 레벨 23에서 사용되지 않습니다. 대신 onInflate (Context, AttributeSet, Bundle)를 사용하십시오.

  • void onInflate (컨텍스트 컨텍스트, AttributeSet attrs, Bundle savedInstanceState) // 일반적으로 액티비티의 컨텐트 뷰를 설정함으로써 뷰 레이아웃 인플레이션의 일부로 프래그먼트가 생성 될 때 호출됩니다.

  • void onPause () // 프래그먼트가 더 이상 재개되지 않을 때 호출됩니다.

  • void onResume () // 조각이 사용자에게 보이고 적극적으로 실행 중일 때 호출됩니다.

  • void onSaveInstanceState (Bundle outState) // 조각의 현재 동적 상태를 저장하라는 요청을하기 위해 호출되어 나중에 프로세스의 새 인스턴스에서 재구성 될 수 있습니다.

  • void onStart () // Fragment가 사용자에게 표시 될 때 호출됩니다.

  • void onStop () // Fragment가 더 이상 시작되지 않을 때 호출됩니다.

  • void onViewStateRestored (Bundle savedInstanceState) // 모든 저장된 상태가 프래그먼트의 뷰 계층으로 복원되면 호출됩니다.

비고

조각은 활동에서 사용자 인터페이스의 일부 또는 일부를 나타냅니다. 단일 활동에서 여러 단편을 결합하여 다중 창 UI를 작성하고 여러 활동에서 단편을 재사용 할 수 있습니다. 조각을 활동의 모듈 섹션으로 생각할 수 있습니다.이 섹션은 자체 수명주기를 가지며 자체 입력 이벤트를 수신하며 활동이 실행되는 동안 추가 또는 제거 할 수 있습니다 (일종의 "하위 활동"과 유사) 다른 활동에서 재사용).

건설자

모든 조각에는 빈 생성자 가 있어야하므로 활동 상태를 복원 할 때 인스턴스화 할 수 있습니다. 프래그먼트가 다시 인스턴스화될 때 이러한 생성자가 호출되지 않으므로 하위 클래스에는 매개 변수가있는 다른 생성자가없는 것이 좋습니다. 대신 호출자가 setArguments (Bundle)를 사용하여 인수를 제공하고 나중에 getArguments ()를 사용하여 Fragment에서 인수를 검색 할 수 있습니다.

newInstance () 패턴

매개 변수를 사용하여 조각 생성자를 만드는 것이 가능하지만 Android는 조각을 다시 작성할 때 내부적으로 인수가없는 생성자를 호출합니다 (예 : Android의 이유로 인해 복원 된 경우). 이런 이유로 매개 변수가있는 생성자에 의존하는 것은 바람직하지 않습니다.

예상되는 단편 인수가 항상 존재하도록하려면 정적 newInstance() 메소드를 사용하여 단편을 작성하고 원하는 모든 매개 변수를 새 인스턴스를 작성할 때 사용할 수있는 번들에 넣을 수 있습니다.

import android.os.Bundle;
import android.support.v4.app.Fragment;

public class MyFragment extends Fragment
{
  // Our identifier for obtaining the name from arguments
  private static final String NAME_ARG = "name";

  private String mName;

  // Required
  public MyFragment(){}

  // The static constructor.  This is the only way that you should instantiate
  // the fragment yourself
  public static MyFragment newInstance(final String name) {
    final MyFragment myFragment = new MyFragment();
    // The 1 below is an optimization, being the number of arguments that will
    // be added to this bundle.  If you know the number of arguments you will add
    // to the bundle it stops additional allocations of the backing map.  If
    // unsure, you can construct Bundle without any arguments
    final Bundle args = new Bundle(1);

    // This stores the argument as an argument in the bundle.  Note that even if
    // the 'name' parameter is NULL then this will work, so you should consider
    // at this point if the parameter is mandatory and if so check for NULL and
    // throw an appropriate error if so
    args.putString(NAME_ARG, name);

    myFragment.setArguments(args);
    return myFragment;
  }

  @Override
  public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    final Bundle arguments = getArguments();
    if (arguments == null || !arguments.containsKey(NAME_ARG)) {
      // Set a default or error as you see fit
    } else {
      mName = arguments.getString(NAME_ARG);
    }
  }
}

이제, 활동에서 :

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
MyFragment mFragment = MyFragment.newInstance("my name");
ft.replace(R.id.placeholder, mFragment);
//R.id.placeholder is where we want to load our fragment
ft.commit();

이 패턴은 필요한 모든 인수가 생성시 조각으로 전달되도록하는 것이 가장 좋습니다. 시스템이 프래그먼트를 삭제하고 나중에 다시 작성하면 상태를 자동으로 복원하지만 onSaveInstanceState(Bundle) 구현을 제공해야합니다.

백 스택과 정적 패브릭 패턴을 사용하여 조각 간 탐색

먼저, 첫 Fragment 을 처음부터 추가해야합니다. 우리는 작업의 onCreate() 메소드에서이를 수행해야합니다.

if (null == savedInstanceState) {
    getSupportFragmentManager().beginTransaction()
      .addToBackStack("fragmentA")
      .replace(R.id.container, FragmentA.newInstance(), "fragmentA")
      .commit();
}

다음으로 우리는 백 스택을 관리해야합니다. 가장 쉬운 방법은 모든 FragmentTransactions에 사용되는 우리 액티비티에 추가 된 함수를 사용하는 것입니다.

public void replaceFragment(Fragment fragment, String tag) {
    //Get current fragment placed in container
    Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container);

    //Prevent adding same fragment on top
    if (currentFragment.getClass() == fragment.getClass()) {
        return;
    }

    //If fragment is already on stack, we can pop back stack to prevent stack infinite growth
    if (getSupportFragmentManager().findFragmentByTag(tag) != null) {
        getSupportFragmentManager().popBackStack(tag, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

    //Otherwise, just replace fragment
    getSupportFragmentManager()
            .beginTransaction()
            .addToBackStack(tag)
            .replace(R.id.container, fragment, tag)
            .commit();
}

마지막으로 onBackPressed() 에서 사용할 수있는 마지막 Fragment에서 돌아갈 때 onBackPressed() 를 재정 onBackPressed() 응용 프로그램을 종료해야합니다.

@Override
public void onBackPressed() {
    int fragmentsInStack = getSupportFragmentManager().getBackStackEntryCount();
    if (fragmentsInStack > 1) { // If we have more than one fragment, pop back stack
        getSupportFragmentManager().popBackStack();
    } else if (fragmentsInStack == 1) { // Finish activity, if only one fragment left, to prevent leaving empty screen
        finish();
    } else {
        super.onBackPressed();
    }
}

활동에서의 실행 :

replaceFragment(FragmentB.newInstance(), "fragmentB");

활동 외부에서의 실행 ( MainActivity 가 우리의 활동이라고 가정) :

((MainActivity) getActivity()).replaceFragment(FragmentB.newInstance(), "fragmentB");

Bundle을 사용하여 Activity에서 Fragment로 데이터 전달

모든 파편에는 빈 생성자 (즉, 입력 인수가없는 생성자 메서드)가 있어야합니다. 따라서 생성되는 Fragment에 데이터를 전달하려면 setArguments() 메서드를 사용해야합니다. 이 메소드는 데이터를 저장하는 번들을 가져 와서 인수에 번들을 저장합니다. 그런 다음이 Bundle은 onCreate()onCreateView() 에서 Fragment를 호출하여 검색 할 수 있습니다.

활동:

 Bundle bundle = new Bundle();
 String myMessage = "Stack Overflow is cool!";
 bundle.putString("message", myMessage );
 FragmentClass fragInfo = new FragmentClass();
 fragInfo.setArguments(bundle);
 transaction.replace(R.id.fragment_single, fragInfo);
 transaction.commit();

파편:

 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    String myValue = this.getArguments().getString("message");
    ...
 }

콜백 인터페이스를 사용하여 활동으로 이벤트 보내기

단편에서 활동으로 이벤트를 보내야하는 경우, 가능한 해결책 중 하나는 콜백 인터페이스를 정의하고 호스트 활동이이를 구현하도록 요구하는 것입니다.

프래그먼트의 버튼을 클릭하면 액티비티에 콜백 전송

먼저 콜백 인터페이스를 정의하십시오.
public interface SampleCallback {
    void onButtonClicked();
}

다음 단계는이 콜백을 단편에 할당하는 것입니다.

public final class SampleFragment extends Fragment {

    private SampleCallback callback;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof SampleCallback) {
            callback = (SampleCallback) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement SampleCallback");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        callback = null;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.sample, container, false);
        // Add button's click listener
        view.findViewById(R.id.actionButton).setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                callback.onButtonClicked(); // Invoke callback here
            }
        });
        return view;
    }
}

마지막으로 액티비티에서 콜백을 구현합니다.

public final class SampleActivity extends Activity implements SampleCallback {

    // ... Skipped code with settings content view and presenting the fragment

    @Override
    public void onButtonClicked() {
        // Invoked when fragment's button has been clicked
    }
}

파편 사이의 전환을 애니메이션으로 표현

조각 사이의 전환을 애니메이션으로 만들거나 FragmentTransaction 을 표시하거나 숨기는 프로세스에 애니메이션을 적용하려면 FragmentManager 를 사용하여 FragmentManager 을 만듭니다.

단일 FragmentTransaction 의 경우 애니메이션을 수행하는 두 가지 다른 방법이 있습니다. 표준 애니메이션을 사용하거나 사용자 정의 애니메이션을 제공 할 수 있습니다.

표준 애니메이션은 FragmentTransaction.setTransition(int transit) 을 호출하고 FragmentTransaction 클래스에서 사용할 수있는 미리 정의 된 상수 중 하나를 사용하여 지정합니다. 글을 쓰는 시점에서 이러한 상수는 다음과 같습니다.

FragmentTransaction.TRANSIT_NONE
FragmentTransaction.TRANSIT_FRAGMENT_OPEN
FragmentTransaction.TRANSIT_FRAGMENT_CLOSE
FragmentTransaction.TRANSIT_FRAGMENT_FADE

전체 트랜잭션은 다음과 같습니다.

getSupportFragmentManager()
    .beginTransaction()
    .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
    .replace(R.id.contents, new MyFragment(), "MyFragmentTag")
    .commit();

사용자 정의 애니메이션은 FragmentTransaction.setCustomAnimations(int enter, int exit) 또는 FragmentTransaction.setCustomAnimations(int enter, int exit, int popEnter, int popExit) 를 호출하여 지정됩니다.

enterexit 애니메이션은 백 스택에서 파편 조각을 포함하지 않는 FragmentTransaction 대해 재생됩니다. back stack에서 조각을 popExit popEnterpopExit 애니메이션이 재생됩니다.

다음 코드는 한 조각을 슬라이딩 아웃하고 다른 조각을 슬라이딩하여 조각을 대체하는 방법을 보여줍니다.

getSupportFragmentManager()
    .beginTransaction()
    .setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right)
    .replace(R.id.contents, new MyFragment(), "MyFragmentTag")
    .commit();

XML 애니메이션 정의는 objectAnimator 태그를 사용합니다. slide_in_left.xml 의 예는 다음과 같습니다.

<?xml version="1.0" encoding="utf-8"?>
<set>
  <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:propertyName="x" 
    android:valueType="floatType"
    android:valueFrom="-1280"
    android:valueTo="0" 
    android:duration="500"/>
</set>

단편 간의 의사 소통

단편 간의 모든 통신은 활동을 통해 이루어져야합니다. 단편은 활동 없이는 서로 통신 할 수 없습니다 .

추가 리소스

이 샘플에서는 message 를 보내고 받기위한 두 개의 조각 인 SenderFragmentReceiverFragment 를 호스트하는 MainActivity 가 있습니다 ( SenderFragment 단순한 String 임).

SenderFragment 의 Button은 메시지 전송 프로세스를 시작합니다. ReceiverFragment 의 TextView는 메시지를받을 때 업데이트됩니다.

다음은 중요한 코드 행을 설명하는 주석이있는 MainActivity 스 니펫입니다.

// Our MainActivity implements the interface defined by the SenderFragment. This enables
// communication from the fragment to the activity
public class MainActivity extends AppCompatActivity implements SenderFragment.SendMessageListener {

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

/**
 * This method is called when we click on the button in the SenderFragment
 * @param message The message sent by the SenderFragment
 */
@Override
public void onSendMessage(String message) {
    // Find our ReceiverFragment using the SupportFragmentManager and the fragment's id
    ReceiverFragment receiverFragment = (ReceiverFragment)
            getSupportFragmentManager().findFragmentById(R.id.fragment_receiver);

    // Make sure that such a fragment exists
    if (receiverFragment != null) {
        // Send this message to the ReceiverFragment by calling its public method
        receiverFragment.showMessage(message);
    }
}
}

MainActivity 의 레이아웃 파일은 LinearLayout 내부의 두 조각을 호스트합니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.naru.fragmentcommunication.MainActivity">

<fragment
    android:id="@+id/fragment_sender"
    android:name="com.naru.fragmentcommunication.SenderFragment"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    tools:layout="@layout/fragment_sender" />

<fragment
    android:id="@+id/fragment_receiver"
    android:name="com.naru.fragmentcommunication.ReceiverFragment"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    tools:layout="@layout/fragment_receiver" />
</LinearLayout>

SenderFragment 인터페이스 노출 SendMessageListener 하는 데 도움이 MainActivity 에서 버튼시기를 알 SenderFragment 클릭했습니다.

다음은 중요한 코드 행을 설명하는 SenderFragment 코드 스 니펫입니다.

public class SenderFragment extends Fragment {

private SendMessageListener commander;

/**
 * This interface is created to communicate between the activity and the fragment. Any activity
 * which implements this interface will be able to receive the message that is sent by this
 * fragment.
 */
public interface SendMessageListener {
    void onSendMessage(String message);
}

/**
 * API LEVEL >= 23
 * <p>
 * This method is called when the fragment is attached to the activity. This method here will
 * help us to initialize our reference variable, 'commander' , for our interface
 * 'SendMessageListener'
 *
 * @param context
 */
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    // Try to cast the context to our interface SendMessageListener i.e. check whether the
    // activity implements the SendMessageListener. If not a ClassCastException is thrown.
    try {
        commander = (SendMessageListener) context;
    } catch (ClassCastException e) {
        throw new ClassCastException(context.toString()
                + "must implement the SendMessageListener interface");
    }
}

/**
 * API LEVEL < 23
 * <p>
 * This method is called when the fragment is attached to the activity. This method here will
 * help us to initialize our reference variable, 'commander' , for our interface
 * 'SendMessageListener'
 *
 * @param activity
 */
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    // Try to cast the context to our interface SendMessageListener i.e. check whether the
    // activity implements the SendMessageListener. If not a ClassCastException is thrown.
    try {
        commander = (SendMessageListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + "must implement the SendMessageListener interface");
    }
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                         @Nullable Bundle savedInstanceState) {
    // Inflate view for the sender fragment.
    View view = inflater.inflate(R.layout.fragment_receiver, container, false);

    // Initialize button and a click listener on it
    Button send = (Button) view.findViewById(R.id.bSend);
    send.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            // Sanity check whether we were able to properly initialize our interface reference
            if (commander != null) {

                // Call our interface method. This enables us to call the implemented method
                // in the activity, from where we can send the message to the ReceiverFragment.
                commander.onSendMessage("HELLO FROM SENDER FRAGMENT!");
            }
        }
    });

    return view;
}
}

SenderFragment 의 레이아웃 파일 :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

<Button
    android:id="@+id/bSend"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="SEND"
    android:layout_gravity="center_horizontal" />
</LinearLayout>

ReceiverFragment 는 간단하며 TextView를 업데이트하는 간단한 public 메서드를 제공합니다. MainActivitySenderFragment 에서 메시지를 받으면 ReceiverFragment public 메서드를 호출합니다.

다음은 중요한 코드 행을 설명하는 주석이있는 ReceiverFragment 의 코드 스 니펫입니다.

public class ReceiverFragment extends Fragment {
TextView tvMessage;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                         @Nullable Bundle savedInstanceState) {
    // Inflate view for the sender fragment.
    View view = inflater.inflate(R.layout.fragment_receiver, container, false);

    // Initialize the TextView
    tvMessage = (TextView) view.findViewById(R.id.tvReceivedMessage);

    return view;
}


/**
 * Method that is called by the MainActivity when it receives a message from the SenderFragment.
 * This method helps update the text in the TextView to the message sent by the SenderFragment.
 * @param message Message sent by the SenderFragment via the MainActivity.
 */
public void showMessage(String message) {
    tvMessage.setText(message);
}
}

ReceiverFragment 의 레이아웃 파일 :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">
<TextView
    android:id="@+id/tvReceivedMessage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Waiting for message!" />
</LinearLayout>


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow