Как передавать данные между фрагментами
Я пытаюсь передать данные между двумя фрагментами в моей программе. Это просто простая строка, которая хранится в списке. Список публикуется во фрагментах A, и когда пользователь нажимает на элемент списка, мне нужно, чтобы он отображался во фрагменте B. поставщик контента, похоже, поддерживает только ID, поэтому это не будет работать. Есть предложения?
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/]. есть полный пример ..
в основном здесь мы имеем дело с коммуникацией между фрагментами. Связь между фрагментами никогда не может быть непосредственно возможной. Он включает в себя деятельность, в контексте которой создаются оба фрагмента.
вам нужно создать интерфейс в отправляющем фрагменте и реализовать интерфейс в действии, которое будет отсрочить сообщение и передать получающему фрагменту.