Как передавать данные между фрагментами


Я пытаюсь передать данные между двумя фрагментами в моей программе. Это просто простая строка, которая хранится в списке. Список публикуется во фрагментах A, и когда пользователь нажимает на элемент списка, мне нужно, чтобы он отображался во фрагменте B. поставщик контента, похоже, поддерживает только ID, поэтому это не будет работать. Есть предложения?

13 71

13 ответов:

Я думаю, что связь между фрагментами должна осуществляться через активность. И связь между фрагментом и активностью может быть выполнена таким образом: https://developer.android.com/training/basics/fragments/communicating.html https://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity

Если вы используете Roboguice, вы можете использовать EventManager в Roboguice для передачи данных без использования действия в качестве интерфейса. Это довольно чистый ИМО.

Если вы не используете Roboguice, вы также можете использовать Otto в качестве шины событий:http://square.github.com/otto/

обновление 20150909: вы также можете использовать зеленую шину событий робота или даже RxJava теперь тоже. Зависит от вашего варианта использования.

С Fragmentдокументация:

часто вы хотите, чтобы один фрагмент взаимодействовал с другим, например, чтобы изменить содержимое на основе события пользователя. Вся связь фрагмент-фрагмент осуществляется через соответствующую деятельность. Два фрагмента никогда не должны общаться напрямую.

поэтому я предлагаю вам посмотреть на базовый фрагмент обучения docs в документации. Они довольно всеобъемлющи с помощью пример и пошаговое руководство.

почему бы вам не использовать пакет. Из первого фрагмента, вот как его настроить:

Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.setArguments(bundle);

затем во втором фрагменте извлеките данные, используя:

Bundle bundle = this.getArguments();
int myInt = bundle.getInt(key, defaultValue);

Bundle поставил методы для множества типов данных. Пожалуйста, смотрите http://developer.android.com/reference/android/os/Bundle.html

Итак, допустим, у вас есть активность AB, которая контролирует фрагмент A и фрагмент B. Внутри фрагмента A вам нужен интерфейс, который может реализовать Activity AB. В примере кода android они имеют:

private Callbacks mCallbacks = sDummyCallbacks;

/*интерфейс обратного вызова, который должны реализовать все действия, содержащие этот фрагмент. Этот механизм позволяет уведомлять действия о выборе элементов. * /

public interface Callbacks {
/*Callback for when an item has been selected. */    
      public void onItemSelected(String id);
}

/*A dummy implementation of the {@link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity. */    
private static Callbacks sDummyCallbacks = new Callbacks() {
    @Override
    public void onItemSelected(String id) {
    }
};

интерфейс обратного вызова помещается внутри одного из ваших фрагментов (скажем, фрагмент Ля.) Я думаю, что цель этого интерфейса обратных вызовов похожа на вложенный класс внутри Frag A, который может реализовать любая деятельность. Поэтому, если фрагмент A был телевизором, обратные вызовы-это пульт дистанционного управления телевизором (интерфейс), который позволяет фрагменту A использоваться Activity AB. Я могу ошибаться в деталях, потому что я нуб, но я получил свою программу, чтобы работать отлично на всех размерах экрана, и это то, что я использовал.

Итак, внутри фрагмента A мы имеем: (Я взял это из образца Android программы)

@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mCallbacks.onItemSelected(DummyContent.ITEMS.get(position).id);
//mCallbacks.onItemSelected( PUT YOUR SHIT HERE. int, String, etc.);
//mCallbacks.onItemSelected (Object);
}

и внутри Activity AB мы переопределяем метод onItemSelected:

public class AB extends FragmentActivity implements ItemListFragment.Callbacks {
//...
@Override
//public void onItemSelected (CATCH YOUR SHIT HERE) {
//public void onItemSelected (Object obj) {
    public void onItemSelected(String id) {
    //Pass Data to Fragment B. For example:
    Bundle arguments = new Bundle();
    arguments.putString(“FragmentB_package”, id);
    FragmentB fragment = new FragmentB();
    fragment.setArguments(arguments);
    getSupportFragmentManager().beginTransaction().replace(R.id.item_detail_container, fragment).commit();
    }

Итак, внутри Activity AB вы в основном бросаете все в пакет и передаете его B. Если вы не уверены, как использовать пакет, посмотрите класс.

Я в основном иду по образцу кода, который предоставил Android. Тот, что с дурацким содержимым. Когда вы создаете новый пакет приложений для Android, он называется MasterDetailFlow.

1 - Первый способ определить интерфейс

public interface OnMessage{
    void sendMessage(int fragmentId, String message);
}

public interface OnReceive{
    void onReceive(String message);
}

2 - в Вас активность реализовать OnMessage интерфейс

public class MyActivity implements OnMessage {
   ...
   @Override
   public void sendMessage(int fragmentId, String message){
       Fragment fragment = getSupportFragmentManager().findFragmentById(fragmentId);
       ((OnReceive) fragment).sendMessage();
   }
}

3-в вашем фрагменте реализовать onReceive интерфейс

public class MyFragment implements OnReceive{
    ...
    @Override
    public void onReceive(String message){
        myTextView.setText("Received message:" + message);
    }
}

это шаблонная версия обработки сообщений, передаваемых между фрагментами.

другой способ передачи данных между фрагментами заключается в использовании шины событий.

1-Регистрация / отмена регистрации на шине событий

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

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

2- Определите класс событий

public class Message{
    public final String message;

    public Message(String message){
        this.message = message;
    }
}

3-разместить это событие в любом месте в вашем приложении

EventBus.getDefault().post(new Message("hello world"));

4 - подпишитесь на это событие, чтобы получить его в своем фрагменте

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(Message event){
    mytextview.setText(event.message);
}

дополнительные детали, варианты использования и пример проекта о шаблоне шины событий.

Это зависит от того, как фрагмент структурированной. Если у вас могут быть некоторые методы на статическом классе фрагмента B, а также целевой объект TextView static, вы можете вызвать метод непосредственно на классе фрагмента A. Это лучше, чем прослушиватель, поскольку метод выполняется мгновенно, и нам не нужно иметь дополнительную задачу, которая выполняет прослушивание на протяжении всего действия. Смотрите пример ниже:

Fragment_class_B.setmyText(String yourstring);

На фрагменте B вы можете иметь определенный метод как:

public static void setmyText(final String string) {
myTextView.setText(string);
}

просто не забудьте установить mytextview как статический на фрагменте B и правильно импортировать класс фрагмента B на фрагмент A.

просто сделал процедуру на моем проекте недавно, и это сработало. Надеюсь, это помогло.

вы можете прочитать этот документ .эта концепция хорошо объяснена здесь http://developer.android.com/training/basics/fragments/communicating.html

Я работаю над аналогичным проектом, и я думаю, что мой код может помочь в данной ситуации

вот обзор того, что я делаю

мой проект имеет два фрагмента под названием "FragmentA" и "FragmentB"

-FragmentA содержит один вид списка,когда вы щелкните элемент FragmentA это индекс передается в FragmentB через интерфейс коммуникатора

  • Этот шаблон проектирования полностью основан на концепции интерфейсов java, которая гласит: "ссылочные переменные интерфейса могут ссылаться на объект подкласса"
  • пусть MainActivity реализовать интерфейс, предоставленный fragmentA(в противном случае мы не можем сделать ссылочную переменную интерфейса, чтобы указать на MainActivity)
  • в приведенном ниже коде объект communicator сделан для ссылки на в MainActivity это "объект" с помощью "setCommunicator (Communicatot c) " метод присутствует в fragmentA.
  • Я срабатывания ответить() метод интерфейса от FrgamentA используя ссылку MainActivity.

    интерфейс communcator определяется внутри fragmentA, это должно обеспечить наименьший доступ previlage к коммуникатор интерфейс.

ниже моя полная работа код

FragmentA.java

public class FragmentA extends Fragment implements OnItemClickListener {

ListView list;
Communicator communicater;


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

public void setCommunicator(Communicator c){
    communicater=c;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onActivityCreated(savedInstanceState);
    communicater=(Communicator) getActivity();
    list = (ListView) getActivity().findViewById(R.id.lvModularListView);
    ArrayAdapter<?> adapter = ArrayAdapter.createFromResource(getActivity(),
            R.array.items, android.R.layout.simple_list_item_1);
    list.setAdapter(adapter);
    list.setOnItemClickListener(this);

}

@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int index, long arg3) {
communicater.respond(index);

}

public interface Communicator{
    public void respond(int index);
}

}

fragmentB.java

public class FragmentA extends Fragment implements OnItemClickListener {

ListView list;
Communicator communicater;


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

public void setCommunicator(Communicator c){
    communicater=c;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onActivityCreated(savedInstanceState);
    communicater=(Communicator) getActivity();
    list = (ListView) getActivity().findViewById(R.id.lvModularListView);
    ArrayAdapter<?> adapter = ArrayAdapter.createFromResource(getActivity(),
            R.array.items, android.R.layout.simple_list_item_1);
    list.setAdapter(adapter);
    list.setOnItemClickListener(this);

}

@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int index, long arg3) {
communicater.respond(index);

}

public interface Communicator{
    public void respond(int index);
}

}

MainActivity.java

public class MainActivity extends Activity implements FragmentA.Communicator {
FragmentManager manager=getFragmentManager();
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    FragmentA fragA=(FragmentA) manager.findFragmentById(R.id.fragmenta);
    fragA.setCommunicator(this);


}

@Override
public void respond(int i) {
    // TODO Auto-generated method stub

FragmentB FragB=(FragmentB) manager.findFragmentById(R.id.fragmentb);
FragB.changetext(i);
}



}

В основном реализовать интерфейс для связи между деятельностью и фрагментом.

1) главный activty

public class MainActivity extends Activity implements SendFragment.StartCommunication
{

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

@Override
public void setComm(String msg) {
// TODO Auto-generated method stub
DisplayFragment mDisplayFragment = (DisplayFragment)getFragmentManager().findFragmentById(R.id.fragment2);
if(mDisplayFragment != null && mDisplayFragment.isInLayout())
{
mDisplayFragment.setText(msg);
}
else
{
Toast.makeText(this, "Error Sending Message", Toast.LENGTH_SHORT).show();
}
}
}

2) фрагмент отправителя (фрагмент к действию)

public class SendFragment extends Fragment
{
StartCommunication mStartCommunicationListner;
String msg = "hi";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View mView = (View) inflater.inflate(R.layout.send_fragment, container);
final EditText mEditText = (EditText)mView.findViewById(R.id.editText1);
Button mButton = (Button) mView.findViewById(R.id.button1);
mButton.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
msg = mEditText.getText().toString();
sendMessage();
}
});
return mView;
}

interface StartCommunication
{
public void setComm(String msg);
}

@Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
if(activity instanceof StartCommunication)
{
mStartCommunicationListner = (StartCommunication)activity;
}
else
throw new ClassCastException();

}

public void sendMessage()
{
mStartCommunicationListner.setComm(msg);
}

}

3) фрагмент приемника (активность к фрагменту)

    public class DisplayFragment extends Fragment
{
View mView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
mView = (View) inflater.inflate(R.layout.display_frgmt_layout, container);
return mView;
}

void setText(String msg)
{
TextView mTextView = (TextView) mView.findViewById(R.id.textView1);
mTextView.setText(msg);
}

}

я использовал эту ссылку для того же решения, я надеюсь, что кто-то найдет его полезным. Очень простой и простой образец.

http://infobloggall.com/2014/06/22/communication-between-activity-and-fragments/

в моем случае я должен был отправить данные назад из FragmentB - > FragmentA следовательно намерения не было вариантом, как фрагмент уже будет инициализирован все все выше ответы звучит хорошо, что это занимает много кода котельной плиты для реализации, так что я пошел с гораздо простой подход С помощью LocalBroadcastManager, это точно делает выше сказанное, но без alll противный шаблонный код. Пример разделено ниже.

В Отправке Фрагмента (Фрагмент B)

public class FragmentB {

    private void sendMessage() {
      Intent intent = new Intent("custom-event-name");
      intent.putExtra("message", "your message");
      LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }
 }

и в полученном сообщении фрагмент (фрагмент а)

  public class FragmentA {
    @Override
    public void onCreate(Bundle savedInstanceState) {

      ...

      // Register receiver
      LocalBroadcastManager.getInstance(this).registerReceiver(receiver,
          new IntentFilter("custom-event-name"));
    }

//    This will be called whenever an Intent with an action named "custom-event-name" is broadcasted.
    private BroadcastReceiver receiver = new BroadcastReceiver() {
      @Override
      public void onReceive(Context context, Intent intent) {
        String message = intent.getStringExtra("message");
      }
    };
}

надеюсь, что это поможет кому-то

фрагмент класса A

public class CountryListFragment extends ListFragment{

    /** List of countries to be displayed in the ListFragment */

    ListFragmentItemClickListener ifaceItemClickListener;   

    /** An interface for defining the callback method */
    public interface ListFragmentItemClickListener {
    /** This method will be invoked when an item in the ListFragment is clicked */
    void onListFragmentItemClick(int position);
}   

/** A callback function, executed when this fragment is attached to an activity */  
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    try{
        /** This statement ensures that the hosting activity implements ListFragmentItemClickListener */
        ifaceItemClickListener = (ListFragmentItemClickListener) activity;          
    }catch(Exception e){
        Toast.makeText(activity.getBaseContext(), "Exception",Toast.LENGTH_SHORT).show();
    }
}

Фрагмент Класса B

public class CountryDetailsFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    /** Inflating the layout country_details_fragment_layout to the view object v */
    View v = inflater.inflate(R.layout.country_details_fragment_layout, null);

    /** Getting the textview object of the layout to set the details */ 
    TextView tv = (TextView) v.findViewById(R.id.country_details);      

    /** Getting the bundle object passed from MainActivity ( in Landscape   mode )  or from 
     *  CountryDetailsActivity ( in Portrait Mode )  
     * */
    Bundle b = getArguments();

    /** Getting the clicked item's position and setting corresponding  details in the textview of the detailed fragment */
    tv.setText("Details of " + Country.name[b.getInt("position")]);     

    return v;
    }

}

основной класс активности для передачи данных между фрагментами

public class MainActivity extends Activity implements ListFragmentItemClickListener {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}


/** This method will be executed when the user clicks on an item in the listview */
@Override
public void onListFragmentItemClick(int position) {

    /** Getting the orientation ( Landscape or Portrait ) of the screen */
    int orientation = getResources().getConfiguration().orientation;


    /** Landscape Mode */
    if(orientation == Configuration.ORIENTATION_LANDSCAPE ){
        /** Getting the fragment manager for fragment related operations */
        FragmentManager fragmentManager = getFragmentManager();

        /** Getting the fragmenttransaction object, which can be used to add, remove or replace a fragment */
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        /** Getting the existing detailed fragment object, if it already exists. 
         *  The fragment object is retrieved by its tag name  *
         */
Fragment prevFrag = fragmentManager.findFragmentByTag("in.wptrafficanalyzer.country.details");

        /** Remove the existing detailed fragment object if it exists */
        if(prevFrag!=null)
    fragmentTransaction.remove(prevFrag);           

        /** Instantiating the fragment CountryDetailsFragment */
  CountryDetailsFragment fragment = new CountryDetailsFragment();

        /** Creating a bundle object to pass the data(the clicked item's   position) from the activity to the fragment */ 
        Bundle b = new Bundle();

        /** Setting the data to the bundle object */
        b.putInt("position", position);

        /** Setting the bundle object to the fragment */
        fragment.setArguments(b);           

        /** Adding the fragment to the fragment transaction */
        fragmentTransaction.add(R.id.detail_fragment_container,   fragment,"in.wptrafficanalyzer.country.details");

        /** Adding this transaction to backstack */
        fragmentTransaction.addToBackStack(null);

        /** Making this transaction in effect */
        fragmentTransaction.commit();

    }else{          /** Portrait Mode or Square mode */
        /** Creating an intent object to start the CountryDetailsActivity */
        Intent intent = new Intent("in.wptrafficanalyzer.CountryDetailsActivity");

        /** Setting data ( the clicked item's position ) to this intent */
        intent.putExtra("position", position);

        /** Starting the activity by passing the implicit intent */
        startActivity(intent);          
      }
    }
 }

класс активности Detailde

public class CountryDetailsActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    /** Setting the layout for this activity */
    setContentView(R.layout.country_details_activity_layout);

    /** Getting the fragment manager for fragment related operations */
    FragmentManager fragmentManager = getFragmentManager();

    /** Getting the fragmenttransaction object, which can be used to add, remove or replace a fragment */
    FragmentTransaction fragmentTransacton = fragmentManager.beginTransaction();

    /** Instantiating the fragment CountryDetailsFragment */
    CountryDetailsFragment detailsFragment = new CountryDetailsFragment();

    /** Creating a bundle object to pass the data(the clicked item's position) from the activity to the fragment */
    Bundle b = new Bundle();

    /** Setting the data to the bundle object from the Intent*/
    b.putInt("position", getIntent().getIntExtra("position", 0));

    /** Setting the bundle object to the fragment */
    detailsFragment.setArguments(b);

    /** Adding the fragment to the fragment transaction */
    fragmentTransacton.add(R.id.country_details_fragment_container, detailsFragment);       

    /** Making this transaction in effect */
    fragmentTransacton.commit();

    }
}

Массив Стран

public class Country {

/** Array of countries used to display in CountryListFragment */
static String name[] = new String[] {
        "India",
        "Pakistan",
        "Sri Lanka",
        "China",
        "Bangladesh",
        "Nepal",
        "Afghanistan",
        "North Korea",
        "South Korea",
        "Japan",
        "Bhutan"
};
}

для получения более подробной информации посетите эту ссылку [http://wptrafficanalyzer.in/blog/itemclick-handler-for-listfragment-in-android/]. есть полный пример ..

в основном здесь мы имеем дело с коммуникацией между фрагментами. Связь между фрагментами никогда не может быть непосредственно возможной. Он включает в себя деятельность, в контексте которой создаются оба фрагмента.

вам нужно создать интерфейс в отправляющем фрагменте и реализовать интерфейс в действии, которое будет отсрочить сообщение и передать получающему фрагменту.