it-swarm.com.ru

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

В настоящее время у меня есть фрагмент в оверлее. Это для входа в сервис. В приложении для телефона каждый из шагов, которые я хочу показать в оверлее, это их собственные экраны и действия. Процесс входа в систему состоит из 3 частей, каждая из которых имеет свою собственную активность, которая вызывается с помощью startActivityForResult (). 

Теперь я хочу сделать то же самое, используя фрагменты и наложение. Наложение покажет фрагмент, соответствующий каждой деятельности. Проблема заключается в том, что эти фрагменты размещены в действии в Honeycomb API. Я могу заставить работать первый фрагмент, но затем мне нужно запустить ActivityForResult (), что невозможно. Есть ли что-то в духе startFragmentForResult (), где я могу запустить новый фрагмент, и когда это будет сделано, вернуть результат предыдущему фрагменту?

70
CACuzcatlan

Все фрагменты живут внутри деятельности. Запуск фрагмента для результата не имеет особого смысла, потому что деятельность, в которой он находится, всегда имеет к нему доступ, и наоборот. Если Фрагмент должен передать результат, он может получить доступ к своей Деятельности, установить свой результат и завершить его. В случае обмена Фрагментами в одном действии, активность все еще доступна обоим фрагментам, и вся ваша передача сообщений может просто проходить через действие.

Просто помните, что у вас всегда есть связь между фрагментом и его активностью. Начать и закончить с результатом - это механизм связи между действиями - действия могут затем делегировать любую необходимую информацию своим фрагментам.

45
LeffelMania

Если вы хотите, есть несколько способов общения между фрагментами,

setTargetFragment(Fragment fragment, int requestCode)
getTargetFragment()
getTargetRequestCode()

Вы можете перезвонить с помощью этих. 

Fragment invoker = getTargetFragment();
if(invoker != null) {
    invoker.callPublicMethod();
}
53
nagoya0

Мои 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
AlikElzin-kilaka

В вашем фрагменте вы можете вызвать getActivity (). Это даст вам доступ к деятельности, которая создала фрагмент. Оттуда вы можете вызвать свой метод настройки, чтобы установить значения или передать значения.

1
Summved Jain

Мы можем просто поделиться одним и тем же 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(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"
    }

}
0
Levon Petrosyan

Самый простой способ вернуть данные - это 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");
}
0
Kirk_hehe

Существует библиотека 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));
0
Ragunath Jawahar

Еще одна вещь, которую вы можете сделать в зависимости от вашей архитектуры, - это использовать общую ViewModel между фрагментами. Таким образом, в моем случае FragmentA - это форма, а FragmentB - это представление выбора элемента, где пользователь может искать и выбирать элемент, сохраняя его в ViewModel. Затем, когда я возвращаюсь во FragmentA, информация уже сохраняется! 

0
Arjun

Решение с использованием интерфейсов (и 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)
            }
        }
    }
0
JakeSteam