У меня сейчас есть фрагмент в оверлее. Это для входа в сервис. В приложении для телефона каждый шаг, который я хочу показать в оверлее, - это отдельные экраны и действия. Процесс входа состоит из 3 частей, каждая из которых имеет собственное действие, которое вызывается с помощью startActivityForResult ().
Теперь я хочу сделать то же самое, используя фрагменты и наложение. В оверлее будет показан фрагмент, соответствующий каждому действию. Проблема в том, что эти фрагменты размещены в действии в Honeycomb API. Я могу заставить работать первый фрагмент, но затем мне нужно startActivityForResult (), что невозможно. Есть ли что-то в строке startFragmentForResult (), где я могу запустить новый фрагмент, и когда это будет сделано, вернуть результат предыдущему фрагменту?
источник
onActivityResult
при желании обратиться к методу родительского фрагмента .Если хотите, есть несколько способов связи между фрагментами,
setTargetFragment(Fragment fragment, int requestCode) getTargetFragment() getTargetRequestCode()
Вы можете выполнить обратный вызов, используя их
Fragment invoker = getTargetFragment(); if(invoker != null) { invoker.callPublicMethod(); }
источник
setTargetFragment()
.setTargetFragment
в настоящее время не рекомендуется. СмотритеsetResultListener
в stackoverflow.com/a/61881149/2914140 здесь.Мы можем просто использовать одну и ту же ViewModel между фрагментами
SharedViewModel
import android.arch.lifecycle.MutableLiveData import android.arch.lifecycle.ViewModel class SharedViewModel : ViewModel() { val stringData: MutableLiveData<String> by lazy { MutableLiveData<String>() } }
FirstFragment
import android.arch.lifecycle.Observer import android.os.Bundle import android.arch.lifecycle.ViewModelProviders import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup class FirstFragment : Fragment() { private lateinit var sharedViewModel: SharedViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) activity?.run { sharedViewModel = ViewModelProviders.of(activity).get(SharedViewModel::class.java) } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_first, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedViewModel.stringData.observe(this, Observer { dateString -> // get the changed String }) } }
ВторойФрагмент
import android.arch.lifecycle.ViewModelProviders import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGrou class SecondFragment : Fragment() { private lateinit var sharedViewModel: SharedViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) activity?.run { sharedViewModel = ViewModelProviders.of(activity).get(SharedViewModel::class.java) } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_first, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) changeString() } private fun changeString() { sharedViewModel.stringData.value = "Test" } }
источник
Недавно Google только что добавил новую возможность,
FragmentManager
благодаря которойFragmentManager
он может выступать в качестве центрального хранилища результатов фрагментов. Мы можем легко передавать данные между фрагментами.Стартовый фрагмент.
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Use the Kotlin extension in the fragment-ktx artifact setResultListener("requestKey") { key, bundle -> // We use a String here, but any type that can be put in a Bundle is supported val result = bundle.getString("bundleKey") // Do something with the result... } }
Фрагмент, результат которого мы хотим вернуть.
button.setOnClickListener { val result = "result" // Use the Kotlin extension in the fragment-ktx artifact setResult("requestKey", bundleOf("bundleKey" to result)) }
Фрагмент взят из официальных документов Google. https://developer.android.com/training/basics/fragments/pass-data-between#kotlin
На момент написания этого ответа эта функция все еще находится в
alpha
состоянии. Вы можете попробовать это, используя эту зависимость.androidx.fragment:fragment:1.3.0-alpha05
источник
Мои 2 цента.
Я переключаюсь между фрагментами, меняя местами старый фрагмент на новый, используя скрыть и показать / добавить (существующий / новый). Итак, этот ответ предназначен для разработчиков, которые используют фрагменты, как я.
Затем я использую этот
onHiddenChanged
метод, чтобы узнать, что старый фрагмент переключился обратно с нового. См. Код ниже.Перед тем, как покинуть новый фрагмент, я устанавливаю результат в глобальном параметре, который будет запрашиваться старым фрагментом. Это очень наивное решение.
@Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (hidden) return; Result result = Result.getAndReset(); if (result == Result.Refresh) { refresh(); } } public enum Result { Refresh; private static Result RESULT; public static void set(Result result) { if (RESULT == Refresh) { // Refresh already requested - no point in setting anything else; return; } RESULT = result; } public static Result getAndReset() { Result result = RESULT; RESULT = null; return result; } }
источник
getAndReset()
метод?onResume()
вызывается и первый фрагмент при закрытии второго?В вашем фрагменте вы можете вызвать getActivity (). Это даст вам доступ к действию, создавшему фрагмент. Оттуда вы можете вызвать свой метод настройки, чтобы установить значения или передать значения.
источник
Есть Android-библиотека - FlowR которая позволяет запускать фрагменты для результатов.
Запускаем фрагмент для результата.
Flowr.open(RequestFragment.class) .displayFragmentForResults(getFragmentId(), REQUEST_CODE);
Обработка результатов в вызывающем фрагменте.
@Override protected void onFragmentResults(int requestCode, int resultCode, Bundle data) { super.onFragmentResults(requestCode, resultCode, data); if (requestCode == REQUEST_CODE) { if (resultCode == Activity.RESULT_OK) { demoTextView.setText("Result OK"); } else { demoTextView.setText("Result CANCELED"); } } }
Установка результата во Фрагменте.
Flowr.closeWithResults(getResultsResponse(resultCode, resultData));
источник
Решение с использованием интерфейсов (и Kotlin). Основная идея состоит в том, чтобы определить интерфейс обратного вызова, реализовать его в своей деятельности, а затем вызвать его из своего фрагмента.
Сначала создайте интерфейс
ActionHandler
:interface ActionHandler { fun handleAction(actionCode: String, result: Int) }
Затем вызовите это от вашего ребенка (в данном случае вашего фрагмента):
companion object { const val FRAGMENT_A_CLOSED = "com.example.fragment_a_closed" } fun closeFragment() { try { (activity as ActionHandler).handleAction(FRAGMENT_A_CLOSED, 1234) } catch (e: ClassCastException) { Timber.e("Calling activity can't get callback!") } dismiss() }
Наконец, реализуйте это в своем родителе, чтобы получить обратный вызов (в данном случае - Activity):
class MainActivity: ActionHandler { override fun handleAction(actionCode: String, result: Int) { when { actionCode == FragmentA.FRAGMENT_A_CLOSED -> { doSomething(result) } actionCode == FragmentB.FRAGMENT_B_CLOSED -> { doSomethingElse(result) } actionCode == FragmentC.FRAGMENT_C_CLOSED -> { doAnotherThing(result) } } }
источник
Самый простой способ вернуть данные - использовать setArgument (). Например, у вас есть fragment1, который вызывает fragment2, который вызывает fragment3, fragment1 -> framgnet2 -> fargment3
Во фрагменте1
public void navigateToFragment2() { if (fragmentManager == null) return; Fragment2 fragment = Fragment2.newInstance(); String tag = "Fragment 2 here"; fragmentManager.beginTransaction() .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) .add(R.id.flContent, fragment, tag) .addToBackStack(null) .commitAllowingStateLoss(); }
Во фрагменте 2 мы называем фрагмент 3 как обычно
private void navigateToFragment3() { if (fragmentManager == null) return; Fragment3 fragment = new Fragment3(); fragmentManager.beginTransaction() .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) .replace(R.id.flContent, fragment, tag) .addToBackStack(null) .commit(); }
Когда мы закончили нашу задачу во фрагменте 3, теперь мы вызываем это так:
FragmentManager fragmentManager = getActivity().getSupportFragmentManager(); if (fragmentManager == null) return; fragmentManager.popBackStack(); Bundle bundle = new Bundle(); bundle.putString("bundle_filter", "data"); fragmentManager.findFragmentByTag("Fragment 2 here").setArguments(bundle);
Теперь во фрагменте 2 мы можем легко вызвать аргументы
@Override public void onResume() { super.onResume(); Bundle rgs = getArguments(); if (args != null) String data = rgs.getString("bundle_filter"); }
источник
Еще одна вещь, которую вы можете сделать в зависимости от вашей архитектуры, - это использовать общую ViewModel между фрагментами. Итак, в моем случае FragmentA - это форма, а FragmentB - это представление выбора элемента, в котором пользователь может искать и выбирать элемент, сохраняя его в ViewModel. Затем, когда я возвращаюсь к FragmentA, информация уже сохраняется!
источник