IT박스

두 조각 간의 기본 통신

itboxs 2020. 11. 20. 08:46

두 조각 간의 기본 통신


하나 activity - MainActivity있어요. 이 안에 Activityfragments가지가 있는데 둘 다 xml 내에서 선언적으로 생성했습니다.

String사용자가 입력 한 Fragment A텍스트를의 텍스트보기 전달하려고합니다 Fragment B. 그러나 이것은 매우 어려운 것으로 입증되었습니다. 누구든지 내가 이것을 어떻게 얻을 수 있는지 알고 있습니까?

조각이 .NET을 사용하여 해당 활동에 대한 참조를 얻을 수 있다는 것을 알고 있습니다 getActivity(). 그래서 거기서부터 시작할까요?


Android 개발자 페이지를 살펴보세요 : http://developer.android.com/training/basics/fragments/communicating.html#DefineInterface

기본적으로 Fragment A에 인터페이스를 정의하고 Activity가 해당 인터페이스를 구현하도록합니다. 이제 Fragment에서 인터페이스 메서드를 호출 할 수 있으며 Activity가 이벤트를 수신합니다. 이제 활동에서 두 번째 Fragment를 호출하여 수신 된 값으로 textview를 업데이트 할 수 있습니다.

활동이 인터페이스를 구현합니다 (아래 FragmentA 참조).

public class YourActivity implements FragmentA.TextClicked{
    @Override
    public void sendText(String text){
        // Get Fragment B
        FraB frag = (FragB)
            getSupportFragmentManager().findFragmentById(R.id.fragment_b);
        frag.updateText(text);
    }
}

Fragment A는 인터페이스를 정의하고 필요할 때 메서드를 호출합니다.

public class FragA extends Fragment{

    TextClicked mCallback;

    public interface TextClicked{
        public void sendText(String text);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (TextClicked) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                + " must implement TextClicked");
        }
    }

    public void someMethod(){
        mCallback.sendText("YOUR TEXT");
    }

    @Override
    public void onDetach() {
        mCallback = null; // => avoid leaking, thanks @Deepscorn
        super.onDetach();
    }
}

조각 B에는 텍스트로 작업을 수행하는 공용 메서드가 있습니다.

public class FragB extends Fragment{

    public void updateText(String text){
        // Here you have it
    }
}

다른 예 (심지어 일부 문서 이 글을 쓰는 시점에서)는 오래된 사용 onAttach방법을. 다음은 전체 업데이트 된 예입니다.

여기에 이미지 설명 입력

메모

  • 프래그먼트가 서로 또는 활동과 직접 대화하는 것을 원하지 않습니다. 이는 그것들을 특정 활동에 묶고 재사용을 어렵게 만듭니다.
  • 해결책은 활동이 구현할 콜백 리스너 인터페이스를 만드는 것입니다. Fragment가 다른 Fragment 또는 상위 활동에 메시지를 보내려고 할 때 인터페이스를 통해이를 수행 할 수 있습니다.
  • 활동이 자식 조각 공용 메서드와 직접 통신하는 것은 괜찮습니다.
  • 따라서 Activity는 컨트롤러 역할을하여 한 조각에서 다른 조각으로 메시지를 전달합니다.

암호

MainActivity.java

public class MainActivity extends AppCompatActivity implements GreenFragment.OnGreenFragmentListener {

    private static final String BLUE_TAG = "blue";
    private static final String GREEN_TAG = "green";
    BlueFragment mBlueFragment;
    GreenFragment mGreenFragment;

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

        // add fragments
        FragmentManager fragmentManager = getSupportFragmentManager();

        mBlueFragment = (BlueFragment) fragmentManager.findFragmentByTag(BLUE_TAG);
        if (mBlueFragment == null) {
            mBlueFragment = new BlueFragment();
            fragmentManager.beginTransaction().add(R.id.blue_fragment_container, mBlueFragment, BLUE_TAG).commit();
        }

        mGreenFragment = (GreenFragment) fragmentManager.findFragmentByTag(GREEN_TAG);
        if (mGreenFragment == null) {
            mGreenFragment = new GreenFragment();
            fragmentManager.beginTransaction().add(R.id.green_fragment_container, mGreenFragment, GREEN_TAG).commit();
        }
    }

    // The Activity handles receiving a message from one Fragment
    // and passing it on to the other Fragment
    @Override
    public void messageFromGreenFragment(String message) {
        mBlueFragment.youveGotMail(message);
    }
}

GreenFragment.java

public class GreenFragment extends Fragment {

    private OnGreenFragmentListener mCallback;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_green, container, false);

        Button button = v.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String message = "Hello, Blue! I'm Green.";
                mCallback.messageFromGreenFragment(message);
            }
        });

        return v;
    }

    // This is the interface that the Activity will implement
    // so that this Fragment can communicate with the Activity.
    public interface OnGreenFragmentListener {
        void messageFromGreenFragment(String text);
    }

    // This method insures that the Activity has actually implemented our
    // listener and that it isn't null.
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnGreenFragmentListener) {
            mCallback = (OnGreenFragmentListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnGreenFragmentListener");
        }
    }

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

BlueFragment.java

public class BlueFragment extends Fragment {

    private TextView mTextView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_blue, container, false);
        mTextView = v.findViewById(R.id.textview);
        return v;
    }

    // This is a public method that the Activity can use to communicate
    // directly with this Fragment
    public void youveGotMail(String message) {
        mTextView.setText(message);
    }
}

XML

activity_main.xml

<?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:orientation="vertical"
    android:padding="16dp">

    <!-- Green Fragment container -->
    <FrameLayout
        android:id="@+id/green_fragment_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:layout_marginBottom="16dp" />

    <!-- Blue Fragment container -->
    <FrameLayout
        android:id="@+id/blue_fragment_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>

fragment_green.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:background="#98e8ba"
              android:padding="8dp"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <Button
        android:id="@+id/button"
        android:text="send message to blue"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

fragment_blue.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:background="#30c9fb"
              android:padding="16dp"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:id="@+id/textview"
        android:text="TextView"
        android:textSize="24sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

가장 좋고 권장되는 방법은 공유 ViewModel을 사용하는 것입니다.

https://developer.android.com/topic/libraries/architecture/viewmodel#sharing

Google 문서에서 :

public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

public void select(Item item) {
    selected.setValue(item);
}

public LiveData<Item> getSelected() {
    return selected;
}
}


public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
    itemSelector.setOnClickListener(item -> {
        model.select(item);
    });
}
}


public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
    model.getSelected().observe(this, { item ->
       // Update the UI.
    });
}
}

추신 : 두 조각이 직접 통신하지 않습니다.


내 두 조각 A와 B를 고려하고 B에서 A로 데이터를 전달해야한다고 가정합니다.

그런 다음 B에 인터페이스를 만들고 데이터를 기본 활동에 전달합니다. 다른 인터페이스를 만들고 데이터를 조각 A로 전달합니다.

작은 예를 공유 :

조각 A는 다음과 같습니다.

public class FragmentA extends Fragment implements InterfaceDataCommunicatorFromActivity {
public InterfaceDataCommunicatorFromActivity interfaceDataCommunicatorFromActivity;
String data;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    return super.onCreateView(inflater, container, savedInstanceState);
}

@Override
public void updateData(String data) {
    // TODO Auto-generated method stub
    this.data = data;
    //data is updated here which is from fragment B
}

@Override
public void onAttach(Activity activity) {
    // TODO Auto-generated method stub
    super.onAttach(activity);
    try {
        interfaceDataCommunicatorFromActivity = (InterfaceDataCommunicatorFromActivity) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement TextClicked");
    }

}

}

FragmentB는 다음과 같습니다.

class FragmentB extends Fragment {
public InterfaceDataCommunicator interfaceDataCommunicator;

@Override
public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);

    // call this inorder to send Data to interface
    interfaceDataCommunicator.updateData("data");
}

public interface InterfaceDataCommunicator {
    public void updateData(String data);
}

@Override
public void onAttach(Activity activity) {
    // TODO Auto-generated method stub
    super.onAttach(activity);
    try {
        interfaceDataCommunicator = (InterfaceDataCommunicator) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement TextClicked");
    }

}

}

주요 활동은

public class MainActivity extends Activity implements InterfaceDataCommunicator {
public InterfaceDataCommunicatorFromActivity interfaceDataCommunicatorFromActivity;

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

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public void updateData(String data) {
    // TODO Auto-generated method stub
    interfaceDataCommunicatorFromActivity.updateData(data);

}

public interface InterfaceDataCommunicatorFromActivity {
    public void updateData(String data);
}

}

https://github.com/greenrobot/EventBus 또는 http://square.github.io/otto/를 살펴보십시오 .

또는 심지어 ... http://nerds.weddingpartyapp.com/tech/2014/12/24/implementing-an-event-bus-with-rxjava-rxbus/


아키텍처 구성 요소를 사용하여 활동 조각 간의 통신을 구현하는 간단한 방법이 있습니다. ViewModel 및 LiveData를 사용하여 활동 조각간에 데이터를 전달할 수 있습니다.

통신에 관련된 프래그먼트는 활동 라이프 사이클에 연결된 동일한 뷰 모델 객체를 사용해야합니다. 뷰 모델 객체는 데이터가 한 조각에 의해 전달되는 라이브 데이터 객체를 포함하고 두 번째 조각은 LiveData의 변경 사항을 수신하고 조각 1에서 보낸 데이터를 수신합니다.

완전한 예는 http://www.zoftino.com/passing-data-between-android-fragments-using-viewmodel을 참조하십시오 .


"setTargetFragment ()"알아보기

"startActivityForResult ()"가 두 활동 간의 관계를 설정하는 경우 "setTargetFragment ()"는 두 조각 간의 호출자 / 호출 관계를 정의합니다.


내 활동에 모든 조각이 사용할 수있는 인터페이스를 제공합니다. 동일한 활동에 많은 조각이있는 경우 이는 많은 코드 재 작성을 절약하고 유사한 기능을 가진 각 조각에 대한 개별 인터페이스를 만드는 것보다 더 깨끗한 솔루션 / 모듈 식입니다. 나는 또한 그것이 어떻게 모듈 식인지 좋아합니다. 단점은 일부 프래그먼트가 필요하지 않은 기능에 액세스 할 수 있다는 것입니다.

    public class MyActivity extends AppCompatActivity
    implements MyActivityInterface {

        private List<String> mData; 

        @Override
        public List<String> getData(){return mData;}

        @Override
        public void setData(List<String> data){mData = data;}
    }


    public interface MyActivityInterface {

        List<String> getData(); 
        void setData(List<String> data);
    }

    public class MyFragment extends Fragment {

         private MyActivityInterface mActivity; 
         private List<String> activityData; 

         public void onButtonPress(){
              activityData = mActivity.getData()
         }

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

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

최신 정보

이 대답을 무시하십시오. 작동하지 않는다는 것이 아닙니다. 그러나 더 나은 방법이 있습니다. 또한 Android는 프래그먼트 간의 직접 통신을 단호하게 권장합니다. 공식 문서를 참조하십시오 . 팁을 주신 @Wahib Ul Haq 사용자에게 감사드립니다.

원래 답변

글쎄, 당신은 조각 B에 개인 변수와 세터를 만들고 조각 A 자체에서 값을 설정할 수 있습니다.

FragmentB.java

private String inputString;
....
....

public void setInputString(String string){
   inputString = string;
}

FragmentA.java

//go to fragment B

FragmentB frag  = new FragmentB();
frag.setInputString(YOUR_STRING);
//create your fragment transaction object, set animation etc
fragTrans.replace(ITS_ARGUMENTS)

또는 질문에서 제안한대로 활동을 사용할 수 있습니다.


최근에 주석을 사용하여 유형 캐스팅 상용구 코드를 생성하는 라이브러리를 만들었습니다. https://github.com/zeroarst/callbackfragment

여기에 예가 있습니다. TextViewon을 클릭하면 DialogFragment콜백이 트리거 MainActivityonTextClicked다음 MyFagment상호 작용할 인스턴스를 가져옵니다 .

public class MainActivity extends AppCompatActivity implements MyFragment.FragmentCallback, MyDialogFragment.DialogListener {

private static final String MY_FRAGM = "MY_FRAGMENT";
private static final String MY_DIALOG_FRAGM = "MY_DIALOG_FRAGMENT";

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

    getSupportFragmentManager().beginTransaction()
        .add(R.id.lo_fragm_container, MyFragmentCallbackable.create(), MY_FRAGM)
        .commit();

    findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            MyDialogFragmentCallbackable.create().show(getSupportFragmentManager(), MY_DIALOG_FRAGM);
        }
    });
}

Toast mToast;

@Override
public void onClickButton(MyFragment fragment) {
    if (mToast != null)
        mToast.cancel();
    mToast = Toast.makeText(this, "Callback from " + fragment.getTag() + " to " + this.getClass().getSimpleName(), Toast.LENGTH_SHORT);
    mToast.show();
}

@Override
public void onTextClicked(MyDialogFragment fragment) {
    MyFragment myFragm = (MyFragment) getSupportFragmentManager().findFragmentByTag(MY_FRAGM);
    if (myFragm != null) {
        myFragm.updateText("Callback from " + fragment.getTag() + " to " + myFragm.getTag());
    }
}

}

참고 URL : https://stackoverflow.com/questions/13700798/basic-communication-between-two-fragments