프래그먼트와 컨테이너 활동간에 데이터 전달


176

프래그먼트와 컨테이너 활동간에 데이터를 전달하려면 어떻게해야합니까? 의도를 통해 활동간에 데이터를 전달하는 것과 비슷한 것이 있습니까?

나는 이것을 읽었지만별로 도움이되지 않았다 :
http://developer.android.com/guide/topics/fundamentals/fragments.html#CommunicatingWithActivity


충분하지 않습니까? 당신은 당신이 원하는 것을 보낼 수 있습니다, 아마도 당신은 더 설명 할 수 있습니다, 당신은 무엇을 달성하고 싶습니까?
Marcin Milejski

예를 들어 문서에서 액티비티에서 조각으로 또는 그 반대로 값이나 문자열을 전달하는 방법을 이해하지 못했습니다. 감사합니다
tyb

2
조각에서 비동기 적으로 호출을 처리하고 데이터를 반환하는 가장 좋은 방법은 양쪽에 BroadcastReceivers를 구현하는 것입니다. 비 특정 수의 조각으로 작업하는 경우 어쨌든 비 동기화해야합니다.
Marek Sebera

@punisher_malade 아니오, 저를 위해 일합니다
Vadim Kotov

답변:


211

프래그먼트에서을 호출 할 수 있습니다 getActivity().

그러면 프래그먼트를 생성 한 액티비티에 액세스 할 수 있습니다. 거기에서 액티비티에있는 액세서 메소드를 호출 할 수 있습니다.

예를 들어 getResult()활동에서 호출 된 메소드의 경우 :

((MyActivity) getActivity()).getResult();

86
부모 안드로이드 활동이 아닌 활동 내 함수에 액세스하기 때문에 getActivity () 호출을 캐스팅해야합니다. ((MyActivity) getActivity ()). getResult ();
Nick

3
조각에서 활동에 이르기까지 어떻게 백 메소드가 가능합니까?
Vasil Valchev

6
@VasilValchev, 인터페이스를 만들고 활동이 인터페이스를 강제로 구현 한 다음 조각 내에서 메소드를 호출하여 데이터를 전달할 수 있습니다. 활동이 인터페이스를 구현하는지 여부를 확인하려면 onAttach 메소드를 사용하십시오.
Ivan Nikolov

3
@IvanNikolov의 훌륭한 답변. Fragments Training Link
bogdan

8
이것은 좋은 습관이나 패턴이 아닙니다. 인터페이스에 대한 답이 맞습니다.
moictab

303

인터페이스를 사용해보십시오.

데이터를 포함하는 활동으로 다시 전달해야하는 조각은 데이터를 처리하고 전달할 인터페이스를 선언해야합니다. 그런 다음 포함 활동이 해당 인터페이스를 구현하는지 확인하십시오. 예를 들면 다음과 같습니다.

자바

조각에서 인터페이스를 선언하십시오 ...

public interface OnDataPass {
    public void onDataPass(String data);
}

그런 다음 포함하는 클래스의 인터페이스 구현을 다음과 같이 onAttach 메소드의 단편에 연결하십시오.

OnDataPass dataPasser;

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    dataPasser = (OnDataPass) context;
}

프래그먼트 내에서 데이터 전달을 처리해야 할 경우 dataPasser 객체에서 호출하십시오.

public void passData(String data) {
    dataPasser.onDataPass(data);
}

마지막으로, 포함 활동 하는 구현 OnDataPass ...

@Override
public void onDataPass(String data) {
    Log.d("LOG","hello " + data);
}

코 틀린

1 단계. 인터페이스 생성

interface OnDataPass {
    fun onDataPass(data: String)
}

2 단계. 다음과 같이 포함 클래스의 인터페이스 구현을 onAttach 메소드 (YourFragment)의 프래그먼트에 연결하십시오.

lateinit var dataPasser: OnDataPass

override fun onAttach(context: Context) {
    super.onAttach(context)
    dataPasser = context as OnDataPass
}

단계 3. 프래그먼트 내에서 데이터 전달을 처리해야하는 경우 dataPasser 오브젝트에서이를 호출하십시오.

fun passData(data: String){
    dataPasser.onDataPass(data)
}

4 단계. 마지막으로 활동에서 OnDataPass를 구현합니다.

class MyActivity : AppCompatActivity(), OnDataPass {}

override fun onDataPass(data: String) {
    Log.d("LOG","hello " + data)
}

1
요점은 좋은 답변 감사합니다. 이것 또한 여기에 아주 잘 설명되어 있습니다 . 내가 알지 못하는 것은 여러 인터페이스를 구현할 수 있다는 것입니다. 이미 구현 중이며 ActionBar.TabListener추가 인터페이스를 추가해야했습니다.
Eugene van der Merwe

5
이것은 분명히 갈 길이며 내 의견으로는 갈 길입니다. 그리고 활동과 조각 사이의 양방향 상호 작용을 제공합니다. 또한 탭 또는 다중 조각 레이아웃을 통해 하나의 활동에 여러 조각이있을 때 조각 사이에서 통신하는 수단을 허용합니다.
Christopher

1
궁금한 점이 있습니다 ... 공식 답변이며 공식 개발자 사이트에서 이것이 frag-act-frag를 공유하는 올바른 방법이라고 말하지만 getActivity (cast )?
unmultimedio

3
누군가 그렇게하기 위해 추가 인터페이스가 필요한 이유는 무엇입니까? 다음 솔루션이 나쁘거나 더 나은 솔루션이라고 생각하는 이유는 무엇입니까? ((MyActivity) getActivity) .myMethod (...)
spacifici

3
onAttach (Activity activity)는 더 이상 사용되지 않습니다. 대신 onAttach (Context context)를 사용하십시오.
Chris.C

23

가장 쉬운 접근 방법이지만 권장되지 않음

조각에서 활동 데이터에 액세스 할 수 있습니다.

활동:

public class MyActivity extends Activity {

    private String myString = "hello";

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

    public String getMyData() {
        return myString;
    }
}

파편:

public class MyFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        MyActivity activity = (MyActivity) getActivity();
        String myDataFromActivity = activity.getMyData();
        return view;
    }
}

5
이것은 코드에 높은 결합을 추가하고 나쁜 습관입니다. 이제 이외의 활동에 조각을 사용할 수 없습니다MyActivity
AmeyaB

왜 이런 식으로 나쁜 습관으로 간주되고 인터페이스 가이 질문의 해결책일까요?
androidXP

모든 액티비티가 BaseActivity에서 확장되고 BaseActivity activity = (BaseActivity) getActivity (); 그것은 모든 활동에서 작동합니다
자르 E Ahmer에게

21
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    Bundle b = getActivity().getIntent().getExtras();
            wid = b.getString("wid");
            rid = b.getString("rid");
            View view = inflater.inflate(R.layout.categoryfragment, container, false);
    return view;
 }

14
이것은 프래그먼트로 가져 오는 방법이지만 XML 레이아웃 파일에 프래그먼트가있는 경우 프래그먼트를 호출하는 클래스에서 어떻게 설정합니까?
Zapnologica

17

프래그먼트와 컨테이너 활동간에 데이터 전달

활동:

        Bundle bundle = new Bundle();
        bundle.putString("message", "Alo Elena!");
        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");
        ...
        ...
        ...
        }

안녕하세요 @Elenasys. 활동에서 번들 데이터를 단편으로 다시 보낼 수있는 방법 조각에서 활동으로 갔고 이미 작성된 조각으로 돌아 가야합니다 (onStart, onResume, ... 만 호출). 활동에서 얻을 수있는 데이터가 필요합니다. 그것을하는 방법이 있습니까? 아니면 내가 잘못하고 있습니까?
Michal Moravik 19 :

7

이것이 최선의 방법인지 아닌지 모르겠습니다 .Bu에서 Google에서 상당히 오랫동안 검색 해 왔지만 번들에서 컨테이너 활동으로 번들을 전달하는 방법을 찾았지만 발견 한 모든 것은 활동에서 조각으로 데이터를 보내는 것입니다. (나는 초보자이기 때문에 약간 혼란 스러웠다).

나중에 나는 내가 원하는대로 정확하게 일한 내 자신의 것을 시도했다. 그래서 나는 같은 것을 찾고있는 사람과 같은 경우에 여기에 게시 할 것입니다.

// Fragment에서 데이터 전달

Bundle gameData = new Bundle();
        gameData.putStringArrayList(Constant.KEY_PLAYERS_ARR,players);
        gameData.putString(Constant.KEY_TEAM_NAME,custom_team_name);
        gameData.putInt(Constant.KEY_REQUESTED_OVER,requestedOver);

        Intent intent = getActivity().getIntent();
        intent.putExtras(gameData);

// 컨테이너 활동에서 번들에서 데이터 가져 오기

Bundle gameData = getIntent().getExtras();
        if (gameData != null)
        {
            int over = gameData.getInt(Constant.KEY_REQUESTED_OVER);
            ArrayList<String> players = gameData.getStringArrayList(Constant.KEY_PLAYERS_ARR);
            String team = gameData.getString(Constant.KEY_TEAM_NAME);

        }
        else if (gameData == null)
        {
            Toast.makeText(this, "Bundle is null", Toast.LENGTH_SHORT).show();
        }

6

인터페이스는 최고의 솔루션 중 하나입니다.

접착제 인터페이스 :

public interface DataProviderFromActivity {

    public String getName();
    public String getId);

}  

MyActivity :

public class MyActivity implements DataProviderFromActivity{

    String name = "Makarov";
    String id = "sys533";

    ... ... ... ... ... .... .... 
    ... ... ... ... ... .... .... 

    public String getName(){
        return name;
    };
    public String getId(){
        return id;
    };
}

MyFragment :

public class MyFragment extends Fragment{

    String fragName = "";
    String fragId = "";

    ... ... ... ... ... .... .... 
    ... ... ... ... ... .... .... 

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        DataProviderFromActivity myActivity= (DataProviderFromActivity) getActivity();
        fragName = myActivity.getName();
        fragId = myActivity.getId();

        ... ... ... ... ... .... .... 
        ... ... ... ... ... .... .... 

        updateFragmentView();
    }
}

안녕하세요 @HassanMakarov 나는 당신의 인터페이스, 간단하고 깨끗합니다. 그래도 한 가지 문제가 있습니다. 내 뷰 페이저에만 해당되는지 모르겠지만 한 번에 최대 2 개의 조각으로 만 데이터를 가져옵니다. 활동이 생성 될 때 문자열 "Makarov"및 "sys533"이 조각 1 및 2에 나타나지만 조각 2 또는 3을 선택할 때까지 문자열이 조각 3에 나타나지 않습니까? 어떤 아이디어?
JC23

@ JC23 문제가 조각 트랜잭션과 관련이 있다고 생각합니다. MainActivity가 시작될 때 어떤 조각이 설정됩니까?
Hassan Tareq

@ JC23 내가하는 일 : Tab / ViewPager 대신 Toolbar & NavigationView를 사용합니다. onNavigationItemSelected ()에서 조각 트랜잭션을 수행하여 조각을 적절하게 설정합니다.
Hassan Tareq

2

Date Listeners를 구현하는 AppCompatActivity를 사용했습니다. 날짜 범위 선택기를 코딩해야했기 때문에 조각이 필요했습니다. 또한 선택한 날짜를 받아 부모 활동으로 반환하는 컨테이너가 필요했습니다.

컨테이너 활동의 경우 이것은 클래스 선언입니다.

public class AppCompatDateRange extends AppCompatActivity implements
    DateIniRangeFragment.OnDateIniSelectedListener, DateFimRangeFragment.OnDateFimSelectedListener

콜백을위한 인터페이스 :

@Override
public void onDateIniSelected(String dataIni) {
    Log.i("data inicial:", dataIni);
}

@Override
public void onDateFimSelected(String dataFim) {
    Log.i("data final:", dataFim);
}

날짜는 쿼리 선택에서 매개 변수이므로 콜백은 문자열입니다.

프래그먼트 코드 (초기 날짜 프래그먼트 기반) :

public class DateIniRangeFragment extends Fragment {
OnDateIniSelectedListener callbackIni;

private DatePicker startDatePicker;

public DateIniRangeFragment() {
    ///required empty constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

///through this interface the fragment sends data to the container activity
public interface OnDateIniSelectedListener {
    void onDateIniSelected(String dataIni);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ///layout for the fragment
    View v = inflater.inflate(R.layout.date_ini_fragment, container, false);

    ///initial date for the picker, in this case, current date
    startDatePicker = (DatePicker) v.findViewById(R.id.start_date_picker_appcompat);
    Calendar c = Calendar.getInstance();
    int ano = c.get(Calendar.YEAR);
    int mes = c.get(Calendar.MONTH);
    int dia = c.get(Calendar.DAY_OF_MONTH);
    startDatePicker.setSpinnersShown(false);
    startDatePicker.init(ano, mes, dia, dateSetListener);

    return v;
}

///listener that receives the selected date
private DatePicker.OnDateChangedListener dateSetListener = new DatePicker.OnDateChangedListener() {
    public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        if (view.isShown()) { ///if the datepicker is on the screen
            String sDataIni = year + "-" + (monthOfYear + 1) + "-" + dayOfMonth;
            callbackIni.onDateIniSelected(sDataIni); //apply date to callback, string format
        }
    }
};

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

    /*
    * this function guarantees that the container activity implemented the callback interface
    * */
    try {
        callbackIni = (OnDateIniSelectedListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString() + " deve implementar OnDateIniSelectedListener");
    }
}

}

컨테이너 + 조각을 작성하기 위해 FragmentPagerAdapter를 확장하는 사용자 정의 클래스와 함께 ViewPager (AppCompat)를 사용했습니다. 대화 상자가 없습니다.


2

간단하게 사용할 수있는 EventBus를 그것은 쉬운 일 위대한입니다

3 단계의 이벤트 버스

  1. 이벤트를 정의하십시오.

    public static class MessageEvent { /* Additional fields if needed */ }

  2. 구독자 준비 : 구독 방법을 선언하고 주석을 달고 선택적으로 스레드 모드를 지정하십시오.

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event) {/* Do something */};

구독자를 등록 및 등록 취소하십시오. 예를 들어 Android의 경우 활동 및 프래그먼트는 일반적으로 수명주기에 따라 등록해야합니다.

 @Override
 public void onStart() {
     super.onStart();
     EventBus.getDefault().register(this);
 }

 @Override
 public void onStop() {
     super.onStop();
     EventBus.getDefault().unregister(this);
 }
  1. 이벤트 게시 :

    EventBus.getDefault().post(new MessageEvent());


1

나는 이것이 늦을 수도 있다는 것을 안다. 그러나 나는 또한이 질문에서 항상 길을 잃었습니다. 나는이 링크를 공유하고 있습니다 ... 이것은 아마도 내가 웹에서 찾은 최고의 설명 일 것입니다. 이것은 조각 활동조각 조각을 해결합니다 !

정말 잘 풀렸다


0

이것은 나를 위해 일하고 있습니다 ..

활동 에서이 방법을 추가하십시오

    public void GetData(String data)
     {
        // do something with your data        
     }

조각에서이 줄을 추가하십시오

((YourActivity)getContext).GetData("your data here");

0
public class Fragmentdemo extends Fragment {

  public interface onDemoEventListener {
    public void demoEvent(String s);
  }

  onDemoEventListener demoEventListener;

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
        try {
          demoEventListener = (onDemoEventListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement onDemoEventListener");
        }
  }

  final String LOG_TAG = "TAG";

  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragmentdemo, null);

    Button button = (Button) v.findViewById(R.id.button);
    button.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        demoEventListener.someEvent("Test text to Fragment1");
      }
    });
    enter code here
    return v;
  }
}

-12

컨테이너 활동의 조각으로 다른 활동에서 전달 된 데이터를 가져 오는 또 다른 간단한 방법은 다음과 같습니다.

Activity_A => Activity_B (조각)

Activity_A에서 다른 활동으로 데이터 (문자열 여기)를 보내는 것처럼 의도를 만듭니다.

Intent intent = new Intent(getBaseContext(),Activity_B.class);
intent.putExtra("NAME", "Value");
startActivity(intent);

Activity_B에 포함 된 조각에 :

String data = getActivity().getIntent().getExtras();

getBaseContext()다음과 같은 오류가 발생합니다 :The method getBaseContext() is undefined for the type new View.OnClickListener(){}
Si8
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.