Есть ли метод, который работает как исходный фрагмент для результата?

В настоящее время у меня есть фрагмент в оверлее. Это для входа в службу. В приложении для телефона каждый из шагов, которые я хочу показать в наложении, - это их собственные экраны и действия. Есть три части процесса входа в систему, и каждый из них имеет свою собственную деятельность, которая была вызвана с помощью 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. Это упрощает общение между действиями, фрагментами, потоками, службами и т.д. Меньше кода, лучшего качества.