0

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

Как передать значения (float) с одного фрагмента на другой?

Вот содержимое OnClickListener() в fragment1.java:

Fragment fr = new Fragment();
Bundle bundle = new Bundle();
bundle.putFloat("a", a);
fr.setArguments(bundle);
FragmentManager fragmentManager = getFragmentManager();
                    fragmentManager.beginTransaction().replace(R.id.content_frame,  fr).commit();

Фрагмент кода, получающий bundle в fragment3.java:

Bundle test = getArguments();
if (test != null) {
   Float a = test.getFloat("a");
}

Далее идёт построение графика, для которого мне нужно это значение a:

GraphView graph = (GraphView) rootView1.findViewById(R.id.graph);
        series = new LineGraphSeries<DataPoint>();
        for(int i = 0; i < 1000; i++) {
            x = x + 0.1;
            y = x * test.getFloat("a"); //вот здесь я не знаю как использовать эту переменную, если использовать просто a, то её не существует
            series.appendData(new DataPoint(x, y), true, 1000);
        }
        graph.addSeries(series);

Вот часть ошибок из Logcat:

java.lang.NullPointerException: Attempt to invoke virtual method 'float android.os.Bundle.getFloat(java.lang.String)' on a null object reference
        at com.example.quadraticequationsolver.fragment3.onCreateView(fragment3.java:49)
        at android.support.v4.app.Fragment.performCreateView(Fragment.java:2439)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
        at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
        at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:802)
        at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
        at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
        at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
        at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:2243)
        at android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:654)
        at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:146)
        at android.support.v4.view.ViewPager.populate(ViewPager.java:1244)
        at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:669)
        at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:631)
        at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:612)
        at android.support.design.widget.TabLayout$ViewPagerOnTabSelectedListener.onTabSelected(TabLayout.java:2831)
        at android.support.design.widget.TabLayout.dispatchTabSelected(TabLayout.java:1608)
        at android.support.design.widget.TabLayout.selectTab(TabLayout.java:1601)
        at android.support.design.widget.TabLayout.selectTab(TabLayout.java:1569)
        at android.support.design.widget.TabLayout$Tab.select(TabLayout.java:1874)
        at android.support.design.widget.TabLayout$TabView.performClick(TabLayout.java:2059)
        at android.view.View.performClickInternal(View.java:8137)
        at android.view.View.access$3700(View.java:888)
        at android.view.View$PerformClick.run(View.java:30236)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:246)
        at android.app.ActivityThread.main(ActivityThread.java:8633)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)

Вот та самая 49 строка из fragment3.java:

y = x + test.getFloat("a");
  • Можно очень по разному. Например записав данные в файл на девайсе и оттуда в нужном месте их прочитать. Или передавать данные через аргументы фрагмента. Или даже (но лучше так не делать) - через глобальную переменную. – ЮрийСПб Dec 18 '21 at 19:11
  • Мне нужно передать float из fragment1.java в fragment3.java. Можно ли сделать это через intent и как? –  Dec 18 '21 at 19:19
  • И да и нет. Вопрос поставлен некорректно - Intent - не для фрагментов. Возможно, вы путаете это с Bundle - через который можно данные передать. Для этого, создавая экземпляр третьего фрагмента задайте ему в качестве arguments Bundle, в который положите данные. Соответственно в 3 фрагменте вытаскиваете данные из Bundle, взятый через getArguments. – ЮрийСПб Dec 18 '21 at 19:22
  • Это моё первое приложение с фрагментами, и я не знаю как это сделать. Я читал ответы на похожие вопросы на русскоязычном и англоязычном Stackoverflow, но всё равно не понял( –  Dec 18 '21 at 19:23
  • Пробовал сделать как в этом вопросе: https://ru.stackoverflow.com/q/326817/476916, но по какой-то причине приложение вылетает при попытке запуска фрагмента с графиком. –  Dec 18 '21 at 19:25
  • Если вылетает - покажите с какой ошибкой и на какой строчке. Также покажите код с попыткой передачи данных и код с попыткой чтения данных. – ЮрийСПб Dec 18 '21 at 19:27
  • Могу предположить, что вылетает из-за моего безграмотного использования переменной из bundle при построении самого графика. Можете, пожалуйста, показать, как именно использовать bundle для передачи данных от фрагмента к фрагменту? Просто я не совсем понимаю, как это работает и как присвоить переменной значение из bundle. –  Dec 18 '21 at 19:32
  • Не нужно предполагать - причина падения с указанием конкретной строки - в логах. Показывать долго, хоть там и очень просто, т.к., по хорошему, надо показывать всю цепочку выполнения, включая транзакции фрагментов, которые тоже можно несколькими способами сделать. Выяснять какой способ вы используете - не получается - вы не показываете ваш код. Будет проще и быстрее если вы покажите то, что я выше просил. Мне сложно представить (после многих лет передачи данных во фрагменты) что там может быть не понятно - мне лично всё представлется очевидным.Покажите ваш код - я постараюсь показать где ошибка – ЮрийСПб Dec 18 '21 at 19:41
  • Так как я не понял, что означает content_frame, я добавил framelayout с этим id в MainActivity.xml, скорее всего в этом проблема. –  Dec 18 '21 at 19:53
  • В логах очень много ошибок –  Dec 18 '21 at 19:57
  • Передача и получение аргументов - правильные. А вот переключение фрагмента, скорее всего, неправильное. Если у вас 1 фрагмент в контейне активити отображается и второй должен вместо него открываться, то надо использовать не внутренний менеджер фрагментов 1 фрагмента, на менеджер фрагментов из активити. Например так: getActivity().getSupportFragmentManager(). И указывать ID того же контейнера, в коем 1 фрагмент лежит. – ЮрийСПб Dec 18 '21 at 20:29
  • И логи вы не те показываете. В момент падения - будут красные строки с указанием синим цветом строки падения. При этом синие строки будут даже кликабельны и открывать строку на которой падает. Посмотрите вот тут как находить нужные логи: https://ru.stackoverflow.com/a/510756/17609 – ЮрийСПб Dec 18 '21 at 20:29
  • Понял. Исключение вызывает как раз та самая строка из функции с графиком, с которой у меня возникли проблемы. Когда я пишу просто a, он говорит cannot resolve symbol a. –  Dec 18 '21 at 21:00
  • Очень странно. Должно работать. Проверьте несколько раз всю последовательность действий. Возможно, у вас где-то опечатка. Судя по ошибке аргументы у вас - null. Т.е. всё же как-то неправильно их передаёте. У вас в вопросе сейчас актуальный код? Как я понимаю, вы его поменяли согласно моим предположениям в комментариях. – ЮрийСПб Dec 18 '21 at 21:07
  • Нет, в коде пока ничего не менял, не понимаю в чём ошибка. Мне кажется, что это неправильно в коде писать: Float a = test.getFloat("a"); , а при построении графика обращаться к самой переменной из bundle. Возможно надо сделать значение равным 1, если оно равно null или может быть объявить переменную отдельно вне функции с bundle –  Dec 18 '21 at 21:19

2 Answers2

0

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

static float test_var;
Arty Morris
  • 1,503
  • Это не будет работать. Т.е. не будет работать во всех случаях. Либо сборщик мусора удалит данные либо при восстановлении состояния приложения при сворачивании/разворачивании оного переменная сбросится к дефолтному значению. – ЮрийСПб Dec 18 '21 at 21:04
  • Ничего не удаляется и всё прекрасно работает. Даже если фрагмент не запускался визуально. У меня приложение с кучей фрагментов и сервисов, и везде где нужно, я использую статическую переменную. Их у меня достаточно – Arty Morris Dec 18 '21 at 21:10
  • Мне надо получить значение введённое пользователем в EditText, а когда я пишу: static float a = Float.parseFloat(aEt.getText().toString()); , я получаю ошибку: Non-static variable 'aEt' cannot be referenced from a static context, можно ли как-то решить эту проблему? –  Dec 18 '21 at 21:11
  • Во первых, переменную а надо объявить в начале класса, а не при получении значения, иначе доступа к ней не получите из другого фрагмента. Во вторых, что такое eAt? Edittext? И покажите код – Arty Morris Dec 18 '21 at 21:16
  • aEt это EditText с первого фрагмента из которого мне нужно получить значение –  Dec 18 '21 at 21:20
  • Объявите переменную в начале класса, не забудьте инициализировать eAt и работайте. И вы тут недавно, на многие вопросы уже есть ответы, есть ошибка - делайте поиск в Яндексе по ключевым словам, например "cannot be referenced from a static context,", и решений будет очень много. Например https://stackoverflow.com/questions/2559527/non-static-variable-cannot-be-referenced-from-a-static-context – Arty Morris Dec 18 '21 at 21:23
  • Да, в Android Studio я недавно, поэтому не знаю базовых вещей. Я читал, как передавать данные между фрагментами с помощью bundle в других вопросах, но у меня почему-то возникают ошибки. Завтра попробую разобраться со статичной переменной и этим условием, спасибо за совет –  Dec 18 '21 at 21:33
  • @ЮрийСПб, я поддержу Arty Morris, в моём приложении, работающем уж почти пять лет, никогда не было проблем с глобальными static переменными. – DrMcSheen Dec 18 '21 at 23:50
0

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

DrMcSheen
  • 975