onActivityResult()未在新的嵌套片段API中调用

Knu*_*dna 76 android android-fragments android-nested-fragment

我一直在使用Android包含在支持库中的新嵌套片段 API.

我面对嵌套片段的问题是,如果嵌套片段(即通过FragmentManager返回的by 已经添加到另一个片段的片段getChildFragmentManager())调用startActivityForResult(),onActivityResult()则不会调用嵌套片段的方法.但是,父片段onActivityResult()和活动onActivityResult()都会被调用.

我不知道我是否遗漏了有关嵌套片段的内容,但我没想到所描述的行为.下面是重现此问题的代码.如果有人能指出我正确的方向并向我解释我做错了什么,我将非常感激:

package com.example.nestedfragmentactivityresult;

import android.media.RingtoneManager;
import android.os.Bundle;
import android.content.Intent;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends FragmentActivity
{
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        this.getSupportFragmentManager()
            .beginTransaction()
            .add(android.R.id.content, new ContainerFragment())
            .commit();
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        super.onActivityResult(requestCode, resultCode, data);

        // This is called
        Toast.makeText(getApplication(),
            "Consumed by activity",
            Toast.LENGTH_SHORT).show();
    }

    public static class ContainerFragment extends Fragment
    {
        public final View onCreateView(LayoutInflater inflater,
                                       ViewGroup container,
                                       Bundle savedInstanceState)
        {
            View result = inflater.inflate(R.layout.test_nested_fragment_container,
                container,
                false);

            return result;
        }

        public void onActivityCreated(Bundle savedInstanceState)
        {
            super.onActivityCreated(savedInstanceState);
            getChildFragmentManager().beginTransaction()
                .add(R.id.content, new NestedFragment())
                .commit();
        }

        public void onActivityResult(int requestCode,
                                     int resultCode,
                                     Intent data)
        {
            super.onActivityResult(requestCode, resultCode, data);

            // This is called
            Toast.makeText(getActivity(),
                "Consumed by parent fragment",
                Toast.LENGTH_SHORT).show();
        }
    }

    public static class NestedFragment extends Fragment
    {
        public final View onCreateView(LayoutInflater inflater,
                                       ViewGroup container,
                                       Bundle savedInstanceState)
        {
            Button button = new Button(getActivity());
            button.setText("Click me!");
            button.setOnClickListener(new View.OnClickListener()
            {
                public void onClick(View v)
                {
                    Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
                    startActivityForResult(intent, 0);
                }
            });

            return button;
        }

        public void onActivityResult(int requestCode,
                                     int resultCode,
                                     Intent data)
        {
            super.onActivityResult(requestCode, resultCode, data);

            // This is NOT called
            Toast.makeText(getActivity(),
                "Consumed by nested fragment",
                Toast.LENGTH_SHORT).show();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

test_nested_fragment_container.xml是:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

</FrameLayout>
Run Code Online (Sandbox Code Playgroud)

pvs*_*nik 141

我用以下代码解决了这个问题(使用了支持库):

在容器片段中以这种方式覆盖onActivityResult:

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        List<Fragment> fragments = getChildFragmentManager().getFragments();
        if (fragments != null) {
            for (Fragment fragment : fragments) {
                fragment.onActivityResult(requestCode, resultCode, data);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在,嵌套片段将接收对onActivityResult方法的调用.

此外,由于注意到 埃里克Brynsvold在类似的问题,嵌套的片段应该使用它的父片段,而不是简单的startActivityForResult()调用开始活动.因此,在嵌套片段启动活动中:

getParentFragment().startActivityForResult(intent, requestCode);
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的答案.它不仅简单明了,而且通过嵌套片段和活动结果解决了整个较低的16位问题.太好了! (3认同)
  • 仅供参考我在firstfragment中使用带有viewpager的pagertabstrip并在viewpager中加载许多子片段 (2认同)

fay*_*lon 58

是的onActivityResult(),嵌套片段不会以这种方式调用.

onActivityResult的调用序列(在Android支持库中)是

  1. Activity.dispatchActivityResult().
  2. FragmentActivity.onActivityResult().
  3. Fragment.onActivityResult().

在第3步中,片段位于FragmentMananger父级中Activity.所以在你的例子中,它是发现调度的容器片段onActivityResult(),嵌套片段永远不会收到事件.

我认为你必须实现自己的调度ContainerFragment.onActivityResult(),找到嵌套片段并调用将结果和数据传递给它.

  • 针对它提出了一个错误:http://code.google.com/p/android/issues/detail?id = 40537 (6认同)
  • 好的,所以问题是......这是一个预期的行为,还是某种错误?对我来说,至少反直觉的是嵌套片段没有收到活动的结果. (2认同)

whi*_*zle 8

这是我解决它的方式.

在活动中:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    List<Fragment> frags = getSupportFragmentManager().getFragments();
    if (frags != null) {
        for (Fragment f : frags) {
            if (f != null)
                handleResult(f, requestCode, resultCode, data);
        }
    }
}

private void handleResult(Fragment frag, int requestCode, int resultCode, Intent data) {
    if (frag instanceof IHandleActivityResult) { // custom interface with no signitures
        frag.onActivityResult(requestCode, resultCode, data);
    }
    List<Fragment> frags = frag.getChildFragmentManager().getFragments();
    if (frags != null) {
        for (Fragment f : frags) {
            if (f != null)
                handleResult(f, requestCode, resultCode, data);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Yog*_*ity 6

对于使用 NavHostFragment 的带有导航组件的 Androidx

2019 年 9 月 2 日更新的答案

这个问题早在Androidx,当您使用一个活动,你有嵌套的片段内NavHostFragmentonActivityResult()不要求对孩子的片段NavHostFragment

要解决此问题,您需要手动将调用路由到onActivityResult()来自onActivityResult()主机活动的子片段。

以下是如何使用 Kotlin 代码完成此操作。这在onActivityResult()您承载以下内容的主要活动中NavHostFragment

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    val navHostFragment = supportFragmentManager.findFragmentById(R.id.your_nav_host_fragment)
    val childFragments = navHostFragment?.childFragmentManager?.fragments
    childFragments?.forEach { it.onActivityResult(requestCode, resultCode, data) }
}
Run Code Online (Sandbox Code Playgroud)

这将确保onActivityResult()子片段的 被正常调用。

对于 Android 支持库

旧答案

此问题已在Android 支持库 23.2 及更高版本中得到修复。我们不再需要Fragment在 Android 支持库 23.2+ 中做任何额外的事情。onActivityResult()现在Fragment按预期在嵌套中调用。

我刚刚使用 Android 支持库 23.2.1 对其进行了测试,并且可以正常工作。终于我可以有更干净的代码了!

因此,解决方案是开始使用最新的 Android 支持库。