Передача данных из activity в fragment

Здравствуйте, мне очень нужна помощь с передаче данных из activity в fragment.
Fragment находиться во фрейме в этом фрейме а точнее во фрагменте есть Listview с текстом мне нужно перенести с активити число(одно) и добавить к списку по позиции. Проблема в том что массив который должен принимать это число ничего не принимает все остаётся без изменений. пробовала и через Intent и через bundle.Помогите узнать в чем проблема.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
import android.annotation.SuppressLint; import android.content.Intent; import android.os.Bundle; import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; public class SecondFragment extends Fragment { String[] countries = { "lesson1", "jj", "Колумбия", "Чили", "Уругвай"}; ListView countriesList; public static SecondFragment newInstance(int index) { SecondFragment f = new SecondFragment(); // Supply index input as an argument. Bundle args = new Bundle(); args.putInt("index", index); f.setArguments(args); return f; } @SuppressLint("MissingInflatedId") @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_second, container, false); r=view.findViewById(R.id.text); if(getArguments()!=null){ countries[0]=countries[0]+ String.valueOf(getArguments().getInt("index",0)); } countriesList = (ListView) view.findViewById(R.id.list); ArrayAdapterString> adapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, countries); countriesList.setAdapter(adapter); return view; } }
сам активити что должен передать число
SecondFragment.newInstance(5);
Как из фрагмента передать данные в активити
Для передачи данных между двумя Activity используется объект Intent . Через его метод putExtra() можно добавить ключ и связанное с ним значение.
Например, передача из текущей activity в SecondActivity строки «Hello World» с ключом «hello»:
// создание объекта Intent для запуска SecondActivity Intent intent = new Intent(this, SecondActivity.class); // передача объекта с ключом "hello" и значением "Hello World" intent.putExtra("hello", "Hello World"); // запуск SecondActivity startActivity(intent);
Для передачи данных применяется метод putExtra() , который в качестве значения позволяет передать данные простейших типов — String, int, float, double, long, short, byte, char, массивы этих типов, либо объект интерфейса Serializable.
Чтобы получить отправленные данные при загрузке SecondActivity, можно воспользоваться методом get() , в который передается ключ объекта:
Bundle arguments = getIntent().getExtras(); String name = arguments.get("hello").toString(); // Hello World
В зависимости от типа отправляемых данных при их получении мы можем использовать ряд методов объекта Bundle. Все они в качестве параметра принимают ключ объекта. Основные из них:
- get() : универсальный метод, который возвращает значение типа Object. Соответственно поле получения данное значение необходимо преобразовать к нужному типу
- getString() : возвращает объект типа String
- getInt() : возвращает значение типа int
- getByte() : возвращает значение типа byte
- getChar() : возвращает значение типа char
- getShort() : возвращает значение типа short
- getLong() : возвращает значение типа long
- getFloat() : возвращает значение типа float
- getDouble() : возвращает значение типа double
- getBoolean() : возвращает значение типа boolean
- getCharArray() : возвращает массив объектов char
- getIntArray() : возвращает массив объектов int
- getFloatArray() : возвращает массив объектов float
- getSerializable() : возвращает объект интерфейса Serializable
Пусть у нас в проекте будет определено две activity: MainActivity и SecondActivity.
В коде SecondActivity определим получение данных:
package com.example.viewapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; public class SecondActivity extends AppCompatActivity < @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setTextSize(26); textView.setPadding(16, 16, 16, 16); Bundle arguments = getIntent().getExtras(); if(arguments!=null)< String name = arguments.get("name").toString(); String company = arguments.getString("company"); int age = arguments.getInt("age"); textView.setText("Name: " + name + "\nCompany: " + company + "\nAge: " + age); >setContentView(textView); > >
В данном случае в SecondActivity получаем все данных из объекта Bundle и выводим их в текстовое поле TextView. Предполагается, что данной activity будут передаваться три элемента — две строки с ключами name и company и число с ключом price.
Теперь определим передачу в SecondActivity данных. Например, определим для MainActivity следующий интерфейс в файле activity_main.xml :
Здесь определены три текстовых поля для ввода данных и кнопка.
В классе MainActivity определим следующее содержимое:
package com.example.viewapp; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.EditText; public class MainActivity extends AppCompatActivity < @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); >public void onClick(View v) < EditText nameText = findViewById(R.id.name); EditText companyText = findViewById(R.id.company); EditText ageText = findViewById(R.id.age); String name = nameText.getText().toString(); String company = companyText.getText().toString(); int age = Integer.parseInt(ageText.getText().toString()); Intent intent = new Intent(this, SecondActivity.class); intent.putExtra("name", name); intent.putExtra("company", company); intent.putExtra("age", age); startActivity(intent); >>
В обработчике нажатия кнопки получаем введенные в текстовые поля EditText данные и передаем их в объект Intent с помощью метода putExtra() . Затем запускаем SecondActivity.
В итоге при нажатии на кнопку запустится SecondActivity, которая получит некоторые введенные в текстовые поля данные.

Передача сложных объектов
В примере выше передавались простые данные — числа, строки. Но также мы можем передавать более сложные данные. В этом случае используется механизм сериализации. Для этого нажмем на папку пакета, где находятся классы MainActivity и SecondActivity, правой кнопкой мыши и в контекстном меню выберем New -> Java Class :

Назовем новый класс User — пусть он будет представлять пользователя.

Пусть класс User имеет следующий код:
package com.example.viewapp; import java.io.Serializable; public class User implements Serializable < private String name; private String company; private int age; public User(String name, String company, int age)< this.name = name; this.company = company; this.age = age; >public String getName() < return name; >public void setName(String name) < this.name = name; >public String getCompany() < return company; >public void setCompany(String company) < this.company = company; >public int getAge() < return age; >public void setAge(int age) < this.age = age; >>
Стоит отметить, что данный класс реализует интерфейс Serializable . Теперь изменим код MainActivity:
package com.example.viewapp; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.EditText; public class MainActivity extends AppCompatActivity < @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); >public void onClick(View v) < EditText nameText = findViewById(R.id.name); EditText companyText = findViewById(R.id.company); EditText ageText = findViewById(R.id.age); String name = nameText.getText().toString(); String company = companyText.getText().toString(); int age = Integer.parseInt(ageText.getText().toString()); User user = new User(name, company, age); Intent intent = new Intent(this, SecondActivity.class); intent.putExtra(User.class.getSimpleName(), user); startActivity(intent); >>
Теперь вместо трех разрозненных данных передается один объект User. В качестве ключа используется результат метода User.class.getSimpleName() , который по сути возвращает название класса.
И изменим класс SecondActivity:
package com.example.viewapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; public class SecondActivity extends AppCompatActivity < @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); //setContentView(R.layout.activity_second); TextView textView = new TextView(this); textView.setTextSize(26); textView.setPadding(16, 16, 16, 16); Bundle arguments = getIntent().getExtras(); User user; if(arguments!=null)< user = (User) arguments.getSerializable(User.class.getSimpleName()); textView.setText("Name: " + user.getName() + "\nCompany: " + user.getCompany() + "\nAge: " + String.valueOf(user.getAge())); >setContentView(textView); > >
Для получения данных применяется метод getSerializable() , поскольку класс User реализует интерфейс Serializable. Таким образом, мы можем передать один единственый объект вместо набора разрозненных данных.
Как из фрагмента передать данные в активити
Одна activity может использовать несколько фрагментов, например, с одной стороны список, а с другой — детальное описание выбранного элемента списка. В такой конфигурации activity использует два фрагмента, которые между собой должны взаимодействовать. Рассмотрим базовые принципы взаимодействия фрагментов в приложении.
Создадим новый проект с пустой MainActivity. Далее создадим разметку layout для фрагментов. Пусть у нас в приложении будет два фрагмента. Добавим в папку res/layout новый xml-файл fragment_list.xml :
Здесь определен элемент ListView для вывода списка объектов.
И также добавим для другого фрагмента файл разметки fragment_detail.xml :
Оба фрагмента будут предельно простыми: один будет содержать список, а второй — текстовой поле. Логика приложения будет такова: при выборе элемента в списке в одном фрагменте выбранный элемент должен отобразиться в текством поле, которое находится во втором фрагменте.
Затем добавим в проект в одну папку с MainActivity собственно классы фрагментов. Добавим новый класс ListFragment со следующим содержимым:
package com.example.fragmentapp; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import androidx.fragment.app.Fragment; public class ListFragment extends Fragment < interface OnFragmentSendDataListener < void onSendData(String data); >private OnFragmentSendDataListener fragmentSendDataListener; String[] countries = < "Бразилия", "Аргентина", "Колумбия", "Чили", "Уругвай">; @Override public void onAttach(Context context) < super.onAttach(context); try < fragmentSendDataListener = (OnFragmentSendDataListener) context; >catch (ClassCastException e) < throw new ClassCastException(context.toString() + " должен реализовывать интерфейс OnFragmentInteractionListener"); >> @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) < View view = inflater.inflate(R.layout.fragment_list, container, false); // получаем элемент ListView ListView countriesList = view.findViewById(R.id.countriesList); // создаем адаптер ArrayAdapteradapter = new ArrayAdapter(getContext(), android.R.layout.simple_list_item_1, countries); // устанавливаем для списка адаптер countriesList.setAdapter(adapter); // добавляем для списка слушатель countriesList.setOnItemClickListener(new AdapterView.OnItemClickListener() < @Override public void onItemClick(AdapterViewparent, View v, int position, long id) < // получаем выбранный элемент String selectedItem = (String)parent.getItemAtPosition(position); // Посылаем данные Activity fragmentSendDataListener.onSendData(selectedItem); >>); return view; > >
Фрагменты не могут напрямую взаимодействовать между собой. Для этого надо обращаться к контексту, в качестве которого выступает класс Activity. Для обращения к activity, как правило, создается вложенный интерфейс. В данном случае он называется OnFragmentSendDataListener с одним методом.
interface OnFragmentSendDataListener < void onSendData(String data); >private OnFragmentSendDataListener fragmentSendDataListener;
Но чтобы взаимодействовать с другим фрагментом через activity, нам надо прикрепить текущий фрагмент к activity. Для этого в классе фрагмента определен метод onAttach(Context context) . В нем происходит установка объекта OnFragmentSendDataListener :
fragmentSendDataListener = (OnFragmentSendDataListener) context;
При обработке нажатия на элемент в списке мы можем отправить Activity данные о выбранном объекте:
String selectedItem = (String)parent.getItemAtPosition(position); fragmentSendDataListener.onSendData(selectedItem);
Таким образом, при выборе объекта в списке MainActivity получит выбранный объект.
Теперь определим класс для второго фрагмента. Назовем его DetailFragment :
package com.example.fragmentapp; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.fragment.app.Fragment; public class DetailFragment extends Fragment < @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) < return inflater.inflate(R.layout.fragment_detail, container, false); >// обновление текстового поля public void setSelectedItem(String selectedItem) < TextView view = getView().findViewById(R.id.detailsText); view.setText(selectedItem); >>
Задача этого фрагмента — вывод некоторой информации. Так как он не должен передавать никакую информацию другому фрагменту, здесь мы модем ограничиться только переопределением метода onCreateView() , который в качестве визуального интерфейса устанавливает разметку из файла fragment_detail.xml
Но чтобы имитировать взаимодействие между двумя фрагментами, здесь также определен метод setSelectedItem() , который обновляет текст на текстовом поле.
В итоге получится следующая структура:

Теперь изменим файл разметки activity_main.xml :
С помощью двух элементов FragmentContainerView в MainActivity добавляются два выше определенных фрагмента.
И в конце изменим код MainActivity :
package com.example.fragmentapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity implements ListFragment.OnFragmentSendDataListener < @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); >@Override public void onSendData(String selectedItem) < DetailFragment fragment = (DetailFragment) getSupportFragmentManager() .findFragmentById(R.id.detailFragment); if (fragment != null) fragment.setSelectedItem(selectedItem); >>
Для взаимодействия фрагмента ListFragment c другим фрагментом через MainActivity надо, чтобы эта activity реализовывала интерфейс OnFragmentSendDataListener. Для этого реализуем метод onSendData() , который получает фрагмент DetailFragment и вызывает у него метод setSelectedItem()
В итоге получится, что при выборе в списке во фрагменте ListFragment будет срабатывать слушатель списка и в частности его метод onItemClick(AdapterView parent, View v, int position, long id) , который вызовет метод fragmentSendDataListener.onSendData(selectedItem); . fragmentSendDataListener устанавливается как MainActivity, поэтому при этом будет вызван метод setSelectedItem у фрагмента DetailFragment. Таким образом, произойдет взаимодействие между двумя фрагментами.
Если мы запустим проект, то на экран будут выведены оба фрагмента, которые смогут взаимодействовать между собой.

Однако пока фрагменты одинаково выводятся в одной activity как в альбомной, так и в портретной ориентации вне зависимости от устройства. Поэтому оптимизируем приложение.
Современный способ передачи данных между фрагментами
С компонентами Android Jetpack происходит много чего там и здесь. В настоящее время большинство разработчиков склонны использовать Single Activity архитектуру, поэтому взаимодействие между фрагментами становится более важным.
Есть несколько способов коммуникации между фрагментами. Например, с помощью Интерфейсов или общей ViewModel. Но иногда они несут дополнительные накладные расходы. В качестве альтернативы можно использовать setTargetFragment, но теперь он также устарел.
Итак, посмотрим на современный способ.
Если вы нашли опечатку — выделите ее и нажмите Ctrl + Enter! Для связи с нами вы можете использовать info@apptractor.ru.