Есть ли метод, который работает как исходный фрагмент для результата?
В настоящее время у меня есть фрагмент в оверлее. Это для входа в службу. В приложении для телефона каждый из шагов, которые я хочу показать в наложении, - это их собственные экраны и действия. Есть три части процесса входа в систему, и каждый из них имеет свою собственную деятельность, которая была вызвана с помощью startActivityForResult().
Теперь я хочу сделать то же самое, используя фрагменты и оверлей. Наложение будет отображать фрагмент, соответствующий каждой активности. Проблема в том, что эти фрагменты размещены в действии в API Honeycomb. Я могу заставить первый фрагмент работать, но тогда мне нужно запуститьActivityForResult(), что невозможно. Есть ли что-то в начале startFragmentForResult(), где я могу запустить новый фрагмент, и когда это произойдет, верните результат в предыдущий фрагмент?
Ответы
Ответ 1
Все фрагменты живут внутри Деяний. Запуск фрагмента для результата не имеет особого смысла, потому что активность, в которой он находится, всегда имеет к нему доступ, и наоборот. Если фрагмент должен передать результат, он может получить доступ к своей Деятельности и установить ее результат и завершить его. В случае замены фрагментов в одном действии, активность Activity все еще доступна для обоих фрагментов, и вся ваша передача сообщений может просто проходить через Activity.
Просто помните, что у вас всегда есть связь между фрагментом и его активностью. Запуск и завершение результата - это механизм для общения между действиями - The Activities могут затем делегировать любую необходимую информацию своим фрагментам.
Ответ 2
Если вы хотите, есть некоторые способы связи между фрагментами,
setTargetFragment(Fragment fragment, int requestCode)
getTargetFragment()
getTargetRequestCode()
Вы можете выполнить обратный вызов, используя эти функции.
Fragment invoker = getTargetFragment();
if(invoker != null) {
invoker.callPublicMethod();
}
Ответ 3
Мои 2 цента.
Я переключаюсь между фрагментами, заменяя старый фрагмент на новый, используя hide и show/add (существующий/новый). Итак, этот ответ предназначен для разработчиков, которые используют фрагменты, как я.
Затем я использую метод 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;
}
}
Ответ 4
В фрагменте вы можете вызвать getActivity(). Это даст вам доступ к активности, создавшей фрагмент. Оттуда вы можете вызвать свой метод настройки, чтобы установить значения или передать значения.
Ответ 5
Существует библиотека 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));
Ответ 6
Самый простой способ передать данные обратно - setArgument(). Например, у вас есть фрагмент1, который вызывает фрагмент2, который вызывает фрагмент3, фрагмент1 → 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");
}
Ответ 7
Решение с использованием интерфейсов (и 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()
}
Наконец, реализуйте это в своем родителе, чтобы получить обратный вызов (в данном случае, ваша активность):
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)
}
}
}
Ответ 8
Еще одна вещь, которую вы можете сделать в зависимости от вашей архитектуры, - это использовать общую ViewModel между фрагментами. Таким образом, в моем случае FragmentA - это форма, а FragmentB - это представление выбора элемента, где пользователь может искать и выбирать элемент, сохраняя его в ViewModel. Затем, когда я возвращаюсь во FragmentA, информация уже сохраняется!
Ответ 9
Мы можем просто поделиться одной и той же моделью представления между фрагментами
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(this).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
})
}
}
SecondFragment
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(this).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"
}
}
Ответ 10
Вы можете использовать EventBus. Это упрощает общение между действиями, фрагментами, потоками, службами и т.д. Меньше кода, лучшего качества.