有没有一种方法可以像结果的开始片段一样工作?

发布于 2024-11-25 05:49:37 字数 318 浏览 1 评论 0原文

我目前在叠加层中有一个片段。这是用于登录服务的。在手机应用程序中,我想在叠加层中显示的每个步骤都是它们自己的屏幕和活动。登录过程分为 3 个部分,每个部分都有自己的活动,通过 startActivityForResult() 调用。

现在我想使用片段和覆盖层来做同样的事情。叠加层将显示与每个活动相对应的片段。问题是这些片段托管在 Honeycomb API 的活动中。我可以让第一个片段工作,但随后我需要 startActivityForResult(),这是不可能的。是否有类似于 startFragmentForResult() 的东西,我可以在其中启动一个新片段,并在完成后将结果返回到前一个片段?

I currently have a fragment in an overlay. This is for signing in to the service. In the phone app, each of the steps I want to show in the overlay are their own screens and activities. There are 3 parts of the sign-in process and each had their own activity that was called with startActivityForResult().

Now I want to do the same thing using fragments and an overlay. The overlay will show a fragment corresponding to each activity. The problem is that these fragments are hosted in an activity in the Honeycomb API. I can get the first fragment working, but then I need to startActivityForResult(), which isn't possible. Is there something along the lines of startFragmentForResult() where I can kick off a new fragment and when it's done have it return a result to the previous fragment?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

小瓶盖 2024-12-02 05:49:37

所有片段都位于“活动”内。为结果启动一个片段没有多大意义,因为容纳它的活动始终可以访问它,反之亦然。如果Fragment需要传递结果,它可以访问其Activity并设置其结果并完成它。在单个 Activity 中交换 Fragments 的情况下,两个 Fragment 仍然可以访问该 Activity,并且所有消息传递都可以简单地通过该 Activity。

请记住,片段与其活动之间始终保持通信。以结果开始和结束是活动之间通信的机制 - 然后活动可以将任何必要的信息委托给它们的片段。

All of the Fragments live inside Activities. Starting a Fragment for a result doesn't make much sense, because the Activity that houses it always has access to it, and vice versa. If the Fragment needs to pass on a result, it can access its Activity and set its result and finish it. In the case of swapping Fragments in a single Activity, well the Activity is still accessible by both Fragments, and all your message passing can simply go through the Activity.

Just remember that you always have communication between a Fragment and its Activity. Starting for and finishing with a result is the mechanism for communication between Activities - The Activities can then delegate any necessary information to their Fragments.

你的呼吸 2024-12-02 05:49:37

如果您愿意,有一些片段之间通信的方法,

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

您可以使用这些方法进行回调。

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

If you wish, there are some methods for communication between Fragments,

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

You can callback using these.

Fragment invoker = getTargetFragment();
if(invoker != null) {
    invoker.callPublicMethod();
}
檐上三寸雪 2024-12-02 05:49:37

最近,Google 刚刚为 FragmentManager 添加了一项新功能,这使得 FragmentManager 能够充当片段结果的中央存储。我们可以轻松地在 Fragments 之间来回传递数据。

您可以查看我制作的博客文章https: //oozou.com/blog/starting-a-fragment-for-results-in-android-46

起始片段。

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))
}

该片段摘自谷歌官方文档。
https://developer.android.com/training/basics/fragments /pass-data- Between#kotlin

在撰写本答案时,此功能仍处于 alpha 状态。您可以使用此依赖项尝试一下。

androidx.fragment:fragment:1.3.0-alpha05

Recently, Google has just added a new ability to FragmentManager which made the FragmentManager be able to act as a central store for fragment results. We can pass the data back and forth between Fragments easily.

You can out the blog post that I've made https://oozou.com/blog/starting-a-fragment-for-results-in-android-46

Starting fragment.

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...
    }
}

A Fragment that we want the result back.

button.setOnClickListener {
    val result = "result"
    // Use the Kotlin extension in the fragment-ktx artifact
    setResult("requestKey", bundleOf("bundleKey" to result))
}

The snippet is taken from Google's official documents.
https://developer.android.com/training/basics/fragments/pass-data-between#kotlin

At the date of this answer written, this feature is still in alpha state. You can try it out using this dependency.

androidx.fragment:fragment:1.3.0-alpha05
踏雪无痕 2024-12-02 05:49:37

我们可以简单地在片段之间共享相同的 ViewModel

SharedViewModel

import android.arch.lifecycle.MutableLiveData
import android.arch.lifecycle.ViewModel

class SharedViewModel : ViewModel() {

    val stringData: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

}

第一个片段

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"
    }

}

We can simply share the same ViewModel between fragments

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
        })

    }

}

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(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"
    }

}
牵你手 2024-12-02 05:49:37

我的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;
    }
}

My 2 cents.

I switch beween fragments by swapping an old fragment with a new one using hide and show/add (existing/new). So this answer is for devs who use fragments like I do.

Then I use the onHiddenChanged method to know that the old fragment got switched to back from the new one. See code below.

Before leaving the new fragment, I set a result in a global parameter to be queried by the old fragment. This is a very naive solution.

@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;
    }
}
猫腻 2024-12-02 05:49:37

这是一个老问题,但我会尝试更新此处给出的答案。

您可以按照此处使用 FragmentResultListener api。

这样,如果您有两个片段,FragmentOne 导航到 FragmentTwo,您可以将数据从 FragmentTwo 向后传递到 FragmentOne 使用此代码:

class FragmentOne: Fragment() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        setFragmentResultListener("myRequestKey") { _, result ->
            val myString = result.getString("myString", "")
            doSomethingWithMyString(myString)
        }
    }
    ...
}

使用从 androidx.fragment.app.setFragmentResultListener 导入的 setFragmentResultListener
再次

class FragmentTwo: Fragment() {
    ...
    private fun returnToFragmentOne() {
        val bundle = bundleOf(
            "myString" to "My Awesome String Data"
        )
        setFragmentResult("myRequestKey", bundle)
        findNavController().navigateUp()
    }
    ...
}

,从 androidx.fragment.app.setFragmentResult 静态导入 setFragmentResult

这样,第二个片段将调用第一个片段的 onCreate 方法中定义的回调,并使用导航组件返回到它(您可以自由选择其他导航方法)。

An old question, but I'll try to update the answers given here.

You can use the FragmentResultListener api as pointed here.

This way, if you have two fragments, FragmentOne which navigates to FragmentTwo, you can pass data backwards from FragmentTwo to FragmentOne with this code:

class FragmentOne: Fragment() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        setFragmentResultListener("myRequestKey") { _, result ->
            val myString = result.getString("myString", "")
            doSomethingWithMyString(myString)
        }
    }
    ...
}

With setFragmentResultListener imported from androidx.fragment.app.setFragmentResultListener.
And

class FragmentTwo: Fragment() {
    ...
    private fun returnToFragmentOne() {
        val bundle = bundleOf(
            "myString" to "My Awesome String Data"
        )
        setFragmentResult("myRequestKey", bundle)
        findNavController().navigateUp()
    }
    ...
}

Again, with setFragmentResult imported statically from androidx.fragment.app.setFragmentResult.

This way, the second fragment calls the callback defined on the onCreate method of the first and returns to it using the Navigation Component (you are free to choose other navigation method).

九厘米的零° 2024-12-02 05:49:37

有一个 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");
        }
    }
}

将结果设置在 Fragment 中。

Flowr.closeWithResults(getResultsResponse(resultCode, resultData));

There is an Android library - FlowR that allows you to start fragments for results.

Starting a fragment for result.

Flowr.open(RequestFragment.class)
    .displayFragmentForResults(getFragmentId(), REQUEST_CODE);

Handling results in the calling fragment.

@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");
        }
    }
}

Setting the result in the Fragment.

Flowr.closeWithResults(getResultsResponse(resultCode, resultData));
无声情话 2024-12-02 05:49:37

传回数据的最简单方法是使用 setArgument()。例如,您有fragment1,它调用fragment2,而fragment2又调用fragment3,fragment1 -> framgnet2 ->; fargment3

在fragment1中

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();
}

在fragment2中我们照常调用fragment3

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();
}

当我们在fragment3中完成任务后,我们这样调用:

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);

现在在fragment2中我们可以轻松地调用参数

@Override
public void onResume() {
    super.onResume();
    Bundle rgs = getArguments();
    if (args != null) 
        String data = rgs.getString("bundle_filter");
}

The easiest way to pass data back is by setArgument(). For example, you have fragment1 which calls fragment2 which calls fragment3, fragment1 -> framgnet2 -> fargment3

In fragment1

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();
}

In fragment2 we call fragment3 as usual

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();
}

When we finished our task in fragment3 now we call like this:

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);

Now in fragment2 we can easily call arguments

@Override
public void onResume() {
    super.onResume();
    Bundle rgs = getArguments();
    if (args != null) 
        String data = rgs.getString("bundle_filter");
}
眼泪也成诗 2024-12-02 05:49:37

使用接口(和 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)
            }
        }
    }

A solution using interfaces (and Kotlin). The core idea is to define a callback interface, implement it in your activity, then call it from your fragment.

First, create an interface ActionHandler:

interface ActionHandler {
    fun handleAction(actionCode: String, result: Int)
}

Next, call this from your child (in this case, your fragment):

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()
}

Finally, implement this in your parent to receive the callback (in this case, your 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)
            }
        }
    }
巴黎夜雨 2024-12-02 05:49:37

根据您的架构,您可以做的另一件事是在片段之间使用共享 ViewModel。因此,在我的例子中,FragmentA 是一个表单,FragmentB 是一个项目选择视图,用户可以在其中搜索和选择一个项目,并将其存储在 ViewModel 中。然后当我回到FragmentA时,信息已经存储了!

Another thing you could do depending on your architecture is use a shared ViewModel between the fragments. So in my case FragmentA is a form, and FragmentB is a item selection view where the user can search and select an item, storing it in the ViewModel. Then when I come back to FragmentA, the information is already stored !

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文