Передача данных между фрагментами в активность
Мне нужно передать данные между от 5 fragments
к одному Activity
, те fragments
отправлять данные один за другим, когда я достигаю 5-го fragment
тогда мне нужно хранить все 5 fragments
Данные, как мы можем это сделать. любая идея велика.
8 ответов
Передайте данные из каждого фрагмента в действие, когда действие получает все данные, а затем обрабатывает их. Вы можете передавать данные, используя интерфейсы.
Фрагмент:
public class Fragment2 extends Fragment {
public interface onSomeEventListener {
public void someEvent(String s);
}
onSomeEventListener someEventListener;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
someEventListener = (onSomeEventListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement onSomeEventListener");
}
}
final String LOG_TAG = "myLogs";
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment2, null);
Button button = (Button) v.findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
someEventListener.someEvent("Test text to Fragment1");
}
});
return v;
}
}
Деятельность:
public class MainActivity extends Activity implements onSomeEventListener{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Fragment frag2 = new Fragment2();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.fragment2, frag2);
ft.commit();
}
@Override
public void someEvent(String s) {
Fragment frag1 = getFragmentManager().findFragmentById(R.id.fragment1);
((TextView)frag1.getView().findViewById(R.id.textView)).setText("Text from Fragment 2:" + s);
}
}
Следующая ссылка объясняет дизайн для связи между фрагментами.
Чтобы разрешить фрагменту взаимодействовать с его действием, вы можете определить интерфейс в классе Fragment и реализовать его в действии. Фрагмент захватывает реализацию интерфейса во время его метода жизненного цикла onAttach() и может затем вызвать методы интерфейса для связи с Activity.
Вот пример связи Фрагмента с Деятельностью:
public class HeadlinesFragment extends ListFragment {
OnHeadlineSelectedListener mCallback;
// Container Activity must implement this interface
public interface OnHeadlineSelectedListener {
public void onArticleSelected(int position);
}
@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 = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
...
}
Теперь фрагмент может доставлять сообщения в действие, вызывая метод onArticleSelected() (или другие методы в интерфейсе), используя экземпляр mCallback интерфейса OnHeadlineSelectedListener.
Например, следующий метод во фрагменте вызывается, когда пользователь щелкает элемент списка. Фрагмент использует интерфейс обратного вызова для доставки события в родительское действие.
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Send the event to the host activity
mCallback.onArticleSelected(position);
}
Реализуйте интерфейс
Чтобы получить обратные вызовы событий из фрагмента, деятельность, в которой он размещен, должна реализовывать интерфейс, определенный в классе фрагмента.
Например, следующее действие реализует интерфейс из приведенного выше примера.
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
}
}
Доставить сообщение фрагменту
Операция хоста может доставлять сообщения во фрагмент, захватывая экземпляр Fragment с помощью findFragmentById(), а затем напрямую вызывая открытые методы фрагмента.
Например, представьте, что действие, показанное выше, может содержать другой фрагмент, который используется для отображения элемента, указанного данными, возвращенными в вышеупомянутом методе обратного вызова. В этом случае действие может передать информацию, полученную в методе обратного вызова, другому фрагменту, который будет отображать элемент:
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
} else {
// Otherwise, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
Я попробовал все вышеперечисленное, и это не сработало для меня. Вот как я заставил это работать. Я использовал интерфейс как средство для отправки данных из фрагмента в активность.
FragmentToActivity.java
public interface FragmentToActivity {
void communicate(String comm);
}
FragmentOne
public class FragmentOne extends Fragment {
private FragmentToActivity mCallback;
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mCallback = (FragmentToActivity) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement FragmentToActivity");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_login, container,
false);
sendData("Andrews");
return v;
}
@Override
public void onDetach() {
mCallback = null;
super.onDetach();
}
public void onRefresh() {
Toast.makeText(getActivity(), "Fragment : Refresh called.",
Toast.LENGTH_SHORT).show();
}
private void sendData(String comm)
{
mCallback.communicate(comm);
}
}
}
Деятельность первая
public class Account extends AppCompatActivity implements
FragmentToActivity{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
public void communicate(String s) {
Log.d("received", s);
}
}
Вы должны вернуться к информации о деятельности вашего фрагмента. А ваша активность рассылает информацию по ее фрагментам:
// In fragment A
((ParentActivity)getActivity()).dispatchInformations("test");
// In ParentActivity
public void dispatchInformations(String mesg){
fragmentB.sendMessage(mesg);
}
Это основной пример
Библиотека фрагментов предоставляет два варианта связи:
- Общая модель представления
- API результатов фрагментов.
Рекомендуемый вариант зависит от варианта использования. Чтобы поделиться постоянными данными с пользовательскими API, используйте ViewModel. Для получения единовременного результата с данными, которые можно поместить в пакет, используйте API результата фрагмента.
Пожалуйста, прочитайте это https://developer.android.com/guide/fragments/communicate#java.
Вы можете использовать шаблон коммуникатора, описанный в ответах выше. Кроме того, вы можете использовать RxJava2. Для лучшей развязки и эффективности.
1- Создайте автобус:
public final class RxBus {
private static final BehaviorSubject<Object> behaviorSubject
= BehaviorSubject.create();
public static BehaviorSubject<Object> getSubject() {
return behaviorSubject;
}
}
2- активность или фрагмент отправителя
//the data to be passed
MyData data =getMyData();
RxBus.getSubject().onNext(data) ;
3-приемник активности или фрагмент
private Subscription subscription;
public onCreate(Bundle savedInstanceState){
subscription = RxBus.getSubject()
.subscribe(new Subscriber<Object>() {
@Override
public void onNext(Object o) {
if (o instanceof MyData) {
Log.d("tag", (MyData)o.getData();
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
4-отписаться, чтобы избежать утечек памяти:
@Override
protected void onDestroy() {
super.onDestroy();
if(subscription!=null){
subscription.unsubscribe();
}
}
Существует очень простой способ передачи данных из фрагмента в другое действие, отличное от контейнерного.
1) Во фрагменте: когда вы инициируете действие, скажем, onButtonClick, передайте данные, которые вы хотите передать, как дополнительные в вашем намерении, например:
Intent intent = new Intent(getActivity(), MapsActivity.class);
intent.putExtra("data", dataString);
startActivity(intent);
2) В получающем Activity: в вашем методе onCreate создайте Bundle для получения переданной информации, как таковой:
Bundle extras = getIntent().getExtras();
if (extras != null) {
receivingString = extras.getString("data");
} else {
// handle case
}
Надеюсь, это помогло:)
Я искал решение для передачи данных из фрагментов в активность. Вот как я это сделал, и я нашел это наиболее подходящим для того, что мне было нужно.
Я считаю, что лучше всего обмениваться данными и обновлять их с помощью глобального
shared ViewModel
В общей модели ViewModel я храню и обновляю данные, используя изменяемые оперативные данные, и я ограничиваю их областью действия MainActivity. ViewModel является одноэлементным и остается в памяти до тех пор, пока не завершится жизненный цикл активности.
class SharedViewModel: ViewModel() {
private val selectedItems: MutableLiveData<List<Product>> =
MutableLiveData<List<Product>>(listOf())
fun getItems(): LiveData<List<Product>> {
return selectedItems
}
fun sendSelectedItems(items: MutableList<Product>) {
selectedItems.postValue(items)
}
}
MainActivity: AppCompactActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// scope shared view model to MainActivity
// I can access and update data from here
val model = ViewModelProvider(this).get(SharedViewModel::class.java)
}
}
class MyFragment1: Fragment() {
// I'm able to get and update data in the SharedViewModel in fragment
// to activity
private val sharedModel: SharedViewModel by activityViewModels()
}
Кроме того, вы можете добавить обратные вызовы к основной активности. Вы можете использовать интерфейс.
interface IAddListener {
fun sendItems(items: MutableList<Product>?)
}
class MyFragment: Fragment() {
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is IAddListener)
mCallback = context
}
private var mCallback: IAddListener? = null
}
class MainActivity: AppCompactActivity(), IAddToPrintQueueListener {
override fun sendItems(items: MutableList<Product>?) {
// update something
}
}
Вот ссылка на документацию по совместному использованию данных