У меня есть два класса. Первый - это активность, второй - фрагмент, где у меня есть какой-то EditText
. В деятельности у меня есть подкласс с async-task и в методе doInBackground
я получаю некоторый результат, который сохраняю в переменную. Как я могу отправить эту переменную из подкласса "моя деятельность" в этот фрагмент?
Отправить данные из активности на фрагмент в Android
Ответ 1
Из операции вы отправляете данные с намерением как:
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
// set Fragmentclass Arguments
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);
и в методе Fragment onCreateView:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String strtext = getArguments().getString("edttext");
return inflater.inflate(R.layout.fragment, container, false);
}
Ответ 2
Также вы можете получить доступ к данным активности из фрагмента:
Активность:
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;
}
}
Ответ 3
Я нашел много ответов здесь @stackoverflow.com, но определенно это правильный ответ:
"Отправка данных из активности в фрагмент в android".
Активность:
Bundle bundle = new Bundle();
String myMessage = "Stackoverflow is cool!";
bundle.putString("message", myMessage );
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) {
Bundle bundle = this.getArguments();
String myValue = bundle.getString("message");
...
...
...
}
или просто
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
String myValue = this.getArguments().getString("message");
...
...
...
}
Ответ 4
Этот ответ может быть слишком поздно. но это будет полезно для будущих читателей.
У меня есть несколько критериев. Я закодировал для выбора файла от намерения. и выбранный файл для передачи в конкретный фрагмент для дальнейшего процесса. У меня есть много фрагментов, имеющих функциональность выбора файлов. в то время каждый раз проверять условие и получать фрагмент и передавать значение довольно отвратительно. Итак, я решил передать значение с помощью интерфейса.
Шаг 1: Создайте интерфейс в Главном действии.
public interface SelectedBundle {
void onBundleSelect(Bundle bundle);
}
Шаг 2. Создайте ссылку SelectedBundle для той же операции
SelectedBundle selectedBundle;
Шаг 3: создайте метод в той же операции
public void setOnBundleSelected(SelectedBundle selectedBundle) {
this.selectedBundle = selectedBundle;
}
Шаг 4: Необходимо инициализировать ссылку SelectedBundle, для которой все фрагменты нуждаются в функциональности средства выбора файлов. Вы помещаете этот код в свой фрагмент на onCreateView(..)
((MainActivity)getActivity()).setOnBundleSelected(new MainActivity.SelectedBundle() {
@Override
public void onBundleSelect(Bundle bundle) {
updateList(bundle);
}
});
Шаг 5: onActivityResult из MainActivity, передайте значения фрагментам, используя интерфейс.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
selectedBundle.onBundleSelect(bundle);
}
Это все. Реализуйте каждый фрагмент, который вам нужен, в FragmentClass. Ты замечательный. ты сделал. ВОТ ЭТО ДА...
Ответ 5
Основная идея использования фрагментов (F) заключается в создании многократно используемых компонентов пользовательского интерфейса в приложениях для Android. Эти фрагменты содержатся в действиях, и есть общий (лучший) способ создания путей пути связи от A → F и F-A. Необходимо обмениваться между F-F посредством Activity, потому что тогда только фрагменты становятся развязанными и самоподдерживающимися.
Таким образом, передача данных из A → F будет такой же, как объясняется ρяσѕρєя K. В дополнение к этому ответу. После создания фрагментов внутри Activity мы также можем передавать данные методам вызова фрагментов в фрагментах,
Например:
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
articleFrag.updateArticleView(position);
Ответ 6
Лучший и удобный подход - это вызов экземпляра фрагмента и отправка данных в это время. каждый фрагмент по умолчанию имеет метод экземпляра
Например: если ваше имя фрагмента MyFragment
поэтому вы будете называть свой фрагмент из действия следующим образом:
getSupportFragmentManager().beginTransaction().add(R.id.container, MyFragment.newInstance("data1","data2"),"MyFragment").commit();
* R.id.container - это идентификатор моего FrameLayout
поэтому в MyFragment.newInstance( "data1", "data2" ) вы можете отправить данные в фрагмент, а в вашем фрагменте вы получите эти данные в MyFragment newInstance (String param1, String param2 )
public static MyFragment newInstance(String param1, String param2) {
MyFragment fragment = new MyFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
а затем в onCreate методе фрагмента вы получите данные:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
так что теперь mParam1 имеют data1 и mParam2 имеют данные2
теперь вы можете использовать этот mParam1 и mParam2 в своем фрагменте.
Ответ 7
Если вы передадите ссылку на фрагмент (конкретный подкласс) в задачу async, вы можете напрямую обратиться к фрагменту.
Некоторые способы передачи ссылки на фрагмент в асинхронную задачу:
- Если ваша задача async является полноценным классом (
class FooTask extends AsyncTask
), передайте фрагмент в конструктор. - Если ваша задача async является внутренним классом, просто объявите конечную переменную Fragment в области, заданной задачей async, или как поле внешнего класса. Вы сможете получить доступ к этому из внутреннего класса.
Ответ 8
Я хотел бы добавить для начинающих, что разница между двумя наиболее часто задаваемыми ответами здесь заключается в различном использовании фрагмента.
Если вы используете фрагмент в классе java, где у вас есть данные, которые вы хотите передать, вы можете применить первый ответ для передачи данных:
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);
Если, однако, вы используете, например, код по умолчанию, предоставленный Android Studio для фрагментов с вкладками, этот код работать не будет.
Это не будет работать, даже если вы замените PlaceholderFragment по умолчанию на FragmentClasses, и даже если вы исправите FragmentPagerAdapter в новой ситуации, добавив переключатель для getItem() и другой переключатель для getPageTitle() (как показано здесь)
Предупреждение: упомянутый выше клип содержит ошибки кода, которые я объясню позже, но полезно посмотреть, как вы переходите от кода по умолчанию к редактируемому коду для фрагментов с вкладками)! Остальная часть моего ответа имеет гораздо больше смысла, если учесть java-классы и xml файлы из этого клипа (представитель для первого использования фрагментов с вкладками в сценарии новичка).
Основная причина, по которой наиболее одобренный ответ на этой странице не сработает, заключается в том, что в этом коде по умолчанию для фрагментов с вкладками фрагменты используются в другом Java-классе: FragmentPagerAdapter!
Таким образом, для отправки данных у вас возникает желание создать пакет в MotherActivity и передать его в FragmentPagerAdapter, используя ответ № 2.
Только это снова не так. (Возможно, вы могли бы сделать это так, но это просто осложнение, которое на самом деле не нужно).
Я думаю, что правильный/более простой способ сделать это - передать данные непосредственно в рассматриваемый фрагмент, используя ответ № 2. Да, между деятельностью и фрагментом будет жесткая связь, НО, для фрагментов с вкладками, что является своего рода ожидаемым. Я бы даже посоветовал вам создать фрагменты с вкладками внутри Java-класса MotherActivity (в виде подклассов, так как они никогда не будут использоваться вне MotherActivity) - это просто, просто добавьте в Java-класс MotherActivity столько фрагментов, сколько вам нужно, вот так:
public static class Tab1 extends Fragment {
public Tab1() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.your_layout_name_for_fragment_1, container, false);
return rootView;
}
}.
Итак, чтобы передать данные из MotherActivity в такой фрагмент, вам нужно создать частные строки/связки выше onCreate вашей деятельности Mother, которые вы можете заполнить данными, которые хотите передать фрагментам, и передать их через метод, созданный после onCreate (здесь он называется getMyData()).
public class MotherActivity extends Activity {
private String out;
private Bundle results;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mother_activity);
// for example get a value from the previous activity
Intent intent = getIntent();
out = intent.getExtras().getString("Key");
}
public Bundle getMyData() {
Bundle hm = new Bundle();
hm.putString("val1",out);
return hm;
}
}
А затем в классе фрагмента вы используете getMyData:
public static class Tab1 extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public Tab1() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.your_layout_name_for_fragment_1, container, false);
TextView output = (TextView)rootView.findViewById(R.id.your_id_for_a_text_view_within_the_layout);
MotherActivity activity = (MotherActivity)getActivity();
Bundle results = activity.getMyData();
String value1 = results.getString("val1");
output.setText(value1);
return rootView;
}
}
Если у вас есть запросы к базе данных, я советую вам делать их в MotherActivity (и передавать их результаты в виде строк/целых чисел, прикрепленных к ключам внутри пакета, как показано выше), как внутри фрагментов с вкладками, ваш синтаксис станет более сложным ( например, это становится getActivity(), а getIntent становится getActivity(). getIntent), но у вас также есть возможность сделать то, что вы хотите.
Мой совет для начинающих - сосредоточиться на маленьких шагах. Во-первых, получите намерение открыть очень простое действие с вкладками, не передавая НИКАКИХ данных. Это работает? Открывает ли он ожидаемые вами вкладки? Если нет, то почему?
Начните с этого, и применив решения, подобные представленным в этом ролике, посмотрите, чего не хватает. Для этого конкретного клипа файл mainactivity.xml никогда не отображается. Это, безусловно, смущает вас. Но если вы обратите внимание, вы увидите, что, например, контекст (tools: context) неверен в файлах фрагментов xml. Каждый фрагмент XML должен указывать на правильный класс фрагмента (или подкласс, используя разделитель $).
Вы также увидите, что в основной Java-класс активности вам нужно добавить tabLayout.setupWithViewPager(mViewPager) - сразу после строки TabLayout tabLayout = (TabLayout) findViewById (R.id.tabs); без этой строки ваше представление фактически не связано с XML файлами фрагментов, но показывает ТОЛЬКО XML файл основного действия.
В дополнение к строке в Java-классе основного действия в XML файле основного действия необходимо изменить вкладки в соответствии с вашей ситуацией (например, добавить или удалить TabItems). Если у вас нет вкладок в основном XML-задании, возможно, вы не выбрали правильный тип действия при первом его создании (новое действие - действие с вкладками).
Обратите внимание, что в последних 3 параграфах я говорю о видео! Поэтому, когда я говорю основной вид деятельности XML, это основной вид деятельности XML в видео, который в вашей ситуации является XML файлом MotherActivity.
Ответ 9
Очень старый пост, все же я осмелюсь добавить небольшое объяснение, которое было бы полезно для меня.
Технически вы можете напрямую установить элементы любого типа в фрагмент из действия.
Итак, почему Bundle?
Причина очень проста - Bundle обеспечивает единый способ обработки:
- создание/открытие фрагмента
- реконфигурация (поворот экрана) - просто добавьте исходный/обновленный комплект для outState в onSaveInstanceState()
- восстановление приложения после сбора мусора в фоновом режиме (как при реконфигурации).
Вы можете (если вам нравятся эксперименты) создать обходное решение в простых ситуациях, но подход Bundle просто не видит разницы между одним фрагментом и одной тысячей в стоге - он остается простым и понятным.
Почему ответ @Elenasys является самым элегантным и универсальным решением.
И почему ответ, заданный @Martin, имеет ловушки
Ответ 10
Из Activity
вы отправляете данные с Bundle как:
Bundle bundle = new Bundle();
bundle.putString("data", "Data you want to send");
// Your fragment
MyFragment obj = new MyFragment();
obj.setArguments(bundle);
И в Fragment
метод onCreateView получить данные:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
String data = getArguments().getString("data");// data which sent from activity
return inflater.inflate(R.layout.myfragment, container, false);
}
Ответ 11
лучший способ отправки данных из класса активности в фрагмент проходит через методы setter. Как
FragmentClass fragmentClass = new FragmentClass();
fragmentClass.setMyList(mylist);
fragmentClass.setMyString(myString);
fragmentClass.setMyMap(myMap);
и легко получить эти данные из класса.
Ответ 12
Иногда вы можете получать Intent в своей деятельности, и вам нужно передать информацию в ваш рабочий фрагмент.
Даны ответы, если вам нужно запустить фрагмент, но если он все еще работает, setArguments()
не очень полезен.
Другая проблема возникает, если переданная информация приведет к взаимодействию с вашим пользовательским интерфейсом. В этом случае вы не можете назвать что-то вроде myfragment.passData()
, потому что андроид быстро сообщит, что может взаимодействовать только поток, создавший представление.
Итак, мое предложение - использовать приемник. Таким образом, вы можете отправлять данные из любого места, включая активность, но задание будет выполняться в контексте фрагмента.
В фрагменте onCreate()
:
protected DataReceiver dataReceiver;
public static final String REC_DATA = "REC_DATA";
@Override
public void onCreate(Bundle savedInstanceState) {
data Receiver = new DataReceiver();
intentFilter = new IntentFilter(REC_DATA);
getActivity().registerReceiver(dataReceiver, intentFilter);
}
private class DataReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int data= intent.getIntExtra("data", -1);
// Do anything including interact with your UI
}
}
В вашей деятельности:
// somewhere
Intent retIntent = new Intent(RE_DATA);
retIntent.putExtra("data", myData);
sendBroadcast(retIntent);
Ответ 13
Если activity
необходимо сделать fragment
выполнить действие после инициализации, самый простой способ - заставить activity
вызвать метод в экземпляре fragment
. В fragment
добавьте метод:
public class DemoFragment extends Fragment {
public void doSomething(String param) {
// do something in fragment
}
}
а затем в activity
, получите доступ к fragment
с помощью менеджера fragment
и вызовите method
:
public class MainActivity extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DemoFragment fragmentDemo = (DemoFragment)
getSupportFragmentManager().findFragmentById(R.id.fragmentDemo);
fragmentDemo.doSomething("some param");
}
}
а затем activity
может напрямую связываться с fragment
, вызвав это method
.
Ответ 14
Вы можете создать открытый статический метод в фрагменте, где вы получите статическую ссылку на этот фрагмент, а затем передаете данные этой функции и установите эти данные в аргумент в том же методе и получите данные через getArgument on oncreate метод фрагмента и установите данные к локальным переменным.
Ответ 15
Самый умный и проверенный способ передачи данных между фрагментами и активностью - это создание переменных, например:
class StorageUtil {
public static ArrayList<Employee> employees;
}
Затем, чтобы передать данные из фрагмента в активность, мы делаем это в методе onActivityCreated:
//a field created in the sending fragment
ArrayList<Employee> employees;
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
employees=new ArrayList();
//java 7 and above syntax for arraylist else use employees=new ArrayList<Employee>() for java 6 and below
//Adding first employee
Employee employee=new Employee("1","Andrew","Sam","1984-04-10","Male","Ghanaian");
employees.add(employee);
//Adding second employee
Employee employee=new Employee("1","Akuah","Morrison","1984-02-04","Female","Ghanaian");
employees.add(employee);
StorageUtil.employees=employees;
}
Теперь вы можете получить значение StorageUtil.employees со всего мира. Гудлак!
Ответ 16
Используйте следующий интерфейс для связи между активностью и фрагментом
public interface BundleListener {
void update(Bundle bundle);
Bundle getBundle();
}
Или используйте следующий универсальный прослушиватель для двусторонней связи с использованием интерфейса
/**
* Created by Qamar4P on 10/11/2017.
*/
public interface GenericConnector<T,E> {
T getData();
void updateData(E data);
void connect(GenericConnector<T,E> connector);
}
метод показа фрагмента
public static void show(AppCompatActivity activity) {
CustomValueDialogFragment dialog = new CustomValueDialogFragment();
dialog.connector = (GenericConnector) activity;
dialog.show(activity.getSupportFragmentManager(),"CustomValueDialogFragment");
}
вы также можете указать свой контекст на GenericConnector
в onAttach(Context)
в вашей деятельности
CustomValueDialogFragment.show(this);
в вашем фрагменте
...
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
connector.connect(new GenericConnector() {
@Override
public Object getData() {
return null;
}
@Override
public void updateData(Object data) {
}
@Override
public void connect(GenericConnector connector) {
}
});
}
...
public static void show(AppCompatActivity activity, GenericConnector connector) {
CustomValueDialogFragment dialog = new CustomValueDialogFragment();
dialog.connector = connector;
dialog.show(activity.getSupportFragmentManager(),"CustomValueDialogFragment");
}
Примечание. Никогда не используйте его как "".toString().toString().toString();
.
Ответ 17
Мое решение - написать статический метод внутри фрагмента:
public TheFragment setData(TheData data) {
TheFragment tf = new TheFragment();
tf.data = data;
return tf;
}
Таким образом, я уверен, что все данные, которые мне нужны, находятся внутри фрагмента перед любой другой возможной операцией, которая могла бы работать с ней. Также он выглядит более чистым, на мой взгляд.
Ответ 18
Проверьте этот ответ, если вы хотите передать данные фрагменту после создания fooobar.com/questions/35125/...
Ответ 19
Я столкнулся с подобной проблемой при использовании новейшего компонента архитектуры навигации. Попробовал весь вышеупомянутый код с передачей пакета из моей деятельности по вызову во Fragment.
Наилучшим решением, следуя последним тенденциям развития Android, является использование View Model (входит в состав Android Jetpack).
Создайте и инициализируйте класс ViewModel в родительском Activity. Обратите внимание, что эта ViewModel должна быть общей для действия и фрагмента.
Теперь внутри onViewCreated() фрагмента инициализируйте Same ViewModel и настройте Observers для прослушивания полей ViewModel.
Вот полезный, подробный учебник, если вам нужно.
Ответ 20
только что наткнулся на этот вопрос, в то время как большинство методов, описанных выше, будут работать. Я просто хочу добавить, что вы можете использовать Event Bus Library, особенно в сценариях, где компонент (Activity или Fragment) не был создан, он подходит для всех размеров проектов Android и многих вариантов использования. Я лично использовал его в нескольких проектах на PlayStore.
Ответ 21
Добавление к ответу ρяσѕρєя K. При настройке аргумента необходимо поддерживать последовательность выполнения операторов. Например, в последовательности ответов есть:
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
// set Fragmentclass Arguments
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);
Но если вы сначала попытаетесь выделить Фрагмент, а затем выделите объект Bundle и попытайтесь установить его как аргумент выделенного фрагмента, его иногда можно принять за значение null в методе onCreateView внутри фрагмента. Например, используя нижеприведенный сегмент кода, иногда getArguments внутри onCreateView могут возвращать значение null.
Отказоустойчивый сегмент кода:
Fragmentclass fragobj = new Fragmentclass();
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
// set Fragmentclass Arguments
fragobj.setArguments(bundle);
Я столкнулся с той же проблемой довольно давно, но когда я переключил порядок высказываний, моя проблема была решена. Было бы здорово, если бы кто-то мог дать твердую причину такого поведения. Скорее всего, это зависит от времени выполнения. Более опытный человек должен объяснить причину этого.
Ответ 22
В вашей деятельности объявите статическую переменную
public static HashMap<String,ContactsModal> contactItems=new HashMap<String, ContactsModal>();
Тогда в вашем фрагменте сделайте как следуйте
ActivityName.contactItems.put(Number,contactsModal);