76

我有一个用片段替换的活动。该活动采用了一个 Intent,该 Intent 包含有关该活动应该显示哪些数据的一些额外信息。

现在我的 Activity 只是一个片段的包装器,它做同样的工作,如果我用标签在 XML 中声明片段,我如何将该包获取到片段?

如果我要使用 FragmentTransaction 将 Fragment 放入 ViewGroup,我将有机会在 Fragment 构造函数中传递此信息,但我想知道在 XML 中定义片段的情况。

4

6 回答 6

53

现在我的 Activity 只是一个片段的包装器,它做同样的工作,如果我用标签在 XML 中声明片段,我如何将该包获取到片段?

你不能。

但是,欢迎您调用findFragmentById()FragmentManager来检索片段后膨胀,然后在片段上调用一些方法以将数据与其关联。虽然显然不可能setArguments(),但您的片段可以安排通过其他方式( 、 等)在配置更改之后保留数据onSaveInstanceState()本身setRetainInstance(true)

于 2012-10-23T16:10:32.690 回答
49

这不是一种封装的方式,但我最终从父活动中“拉”了包:

Bundle bundle = getActivity().getIntent().getExtras();
于 2015-01-05T11:58:20.530 回答
18

您不能传递 Bundle(除非您以编程方式而不是通过 XML 膨胀片段),但您可以通过 XML 将参数(或更确切地说是属性)传递给片段。

该过程类似于您定义 View 自定义属性的方式。除了 AndroidStudio(当前)在此过程中不为您提供帮助。

假设这是您使用参数的片段(我将使用 kotlin,但它也完全适用于 Java):

class MyFragment: Fragment() {

    // your fragment parameter, a string
    private var screenName: String? = null

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        if (screenName == null) {
            screenName = arguments?.getString("screen_name")
        }
    }
}

你想做这样的事情:

<fragment
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/myFragment"
    android:name="com.example.MyFragment"
    app:screen_name="@string/screen_a"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

注意app:screen_name="@string/screen_a"

要使其正常工作,只需将其添加到值文件中(fragment_attrs.xml或选择您想要的任何名称):

<!-- define your attribute name and type -->
<attr name="screen_name" format="string|reference"/>

<!-- define a bunch of constants you wanna use -->
<string name="screen_a" translatable="false">ScreenA</string>
<string name="screen_b" translatable="false">ScreeenB</string>

<!-- now define which arguments your fragment is gonna have (can be more then one) -->
<!-- the convention is "FragmentClassName_MembersInjector" -->
<declare-styleable name="MyFragment_MembersInjector">
    <attr name="screen_name"/>
</declare-styleable>

差不多完成了,你只需要在你的片段中阅读它,所以添加方法:

override fun onInflate(context: Context?, attrs: AttributeSet?, savedInstanceState: Bundle?) {
    super.onInflate(context, attrs, savedInstanceState)
    if (context != null && attrs != null && screenName == null) {
        val ta = context.obtainStyledAttributes(attrs, R.styleable.MyFragment_MembersInjector)
        if (ta.hasValue(R.styleable.MyFragment_MembersInjector_screen_name)) {
            screenName = ta.getString(R.styleable.MyFragment_MembersInjector_screen_name)
        }
        ta.recycle()
    }
}

etvoilá,您的片段中的 XML 属性 :)

限制:

  • Android Studio(截至目前)不会在布局 XML 中自动完成此类参数
  • 您不能通过Parcelable,但只能通过可以定义为 Android 属性的内容
于 2018-09-13T07:42:58.963 回答
14

另一种选择是不在 XML 中声明片段。我知道这不是你想要做的。但是,您可以在视图中声明一个简单的布局,如下所示:

    <LinearLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" />

然后在您的Activity课程中,您以编程方式使用片段膨胀布局。这样您就可以使用 args 传递参数。

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MyFragment fragment = MyFragment.newInstance();
Bundle args = new Bundle();
args.putInt(Global.INTENT_INT_ROLE, 1);
fragment.setArguments(args);
fragmentTransaction.add(R.id.fragment_container, fragment, "MyActivity");
fragmentTransaction.commit();

在片段中,

if (getArguments() != null) {
   int role = getArguments().getInt(Global.INTENT_INT_ROLE); }

这种方法不像在 xml 中声明它那样干净和简单,但是我已经转移到它,因为它使您可以更好地控制片段。

于 2015-12-21T03:24:20.370 回答
9

我知道答案为时已晚,但我认为有人需要这个:)

只是在活动覆盖onAttachFragment()

@Override
public void onAttachFragment(Fragment fragment)
{
    super.onAttachFragment(fragment);

    if (fragment.getId() == R.id.frgBlank)
    {
        Bundle b = new Bundle();
        b.putString("msg", "Message");

        fragment.setArguments(b);
    }
}

并在片段 onCreateView 方法中

Bundle b = getArguments();
if (b != null)
{
    Toast.makeText(getBaseContext(), b.getString("msg"), Toast.LENGTH_SHORT).show();
}
于 2019-11-07T08:03:21.923 回答
4

我看到的唯一解决方案是不使用参数作为数据交换通道。相反,让您的片段从其他地方获取必要的信息。回调以获取正确的活动,查阅临时存储内存、Singleton 对象等。

另一个可能有用的解决方案是使用允许不相关对象通过 Mediator 设计模式交换消息的框架,例如Otto

于 2014-06-17T14:10:01.010 回答