将初始数据提供给片段的正确方法?

Posted

技术标签:

【中文标题】将初始数据提供给片段的正确方法?【英文标题】:Proper way to give initial data to fragments? 【发布时间】:2012-06-03 15:18:22 【问题描述】:

所以我了解到我需要一个空的构造函数,以使我的片段不会在重新初始化时崩溃。我的问题是我在初始化片段时使用数据列表(至少其中一些)。那么用数据列表开始新片段的好方法是什么。我应该在OnCreate() 中创建一个getData 方法来从其他来源获取数据还是什么是正确的方法?

向捆绑包提供数据确实不是一个很好的方法,因为我有很多数据。

让我们举一个案例(我这样理解更好)。

当用户单击按钮时,片段会启动。我以前做的是这样创建一个新片段:

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    
    fragmentTransaction.replace(R.id.center_container, new DetailFragment(item));
    fragmentTransaction.addToBackStack(DETAIL_TAG);
    
    fragmentTransaction.commit();

然后在我的片段中:

public DetailFragment(EventItem item) 
    mItem = item;
    mPlaces = Database.getContainerPlaces(getActivity()).getValidItems();

我不能将所有数据都提供给一个包,所以这行不通。那我该怎么办?

A:我应该使用空构造函数初始化片段,然后从我的活动中使用 setter 直接在片段中设置数据吗?但是,如果用户按 home 键,android 关闭片段并且用户稍后返回,我不会丢失数据吗?

B:我是否应该使用工厂模式初始化片段并调用setRetainInstance(true),给片段一个用于识别数据的键,然后让片段从某个第三方来源获取 onCreateView 中所需的数据?

C:我应该只创建一个空的构造函数,然后在onCreate() 中获取片段所需的数据吗?

应该注意的是,应用是纵向锁定的,所以问题主要在于在 Android 关闭和用户重新启动时维护对象。

【问题讨论】:

为什么不只创建一个无头片段和 setReatinedInstance(true) 并在片段上放置一个标签,当你重新开始时,然后使用片段管理器中的标签获取片段。您可以将所有数据放在无头片段中,然后调用 getData。是不是很简单! @AZ_ 除了我需要另一个片段来包含视图,这意味着两个片段只会降低代码的可读性。 我认为这将使您的代码更加健壮。只需声明一个内部无头片段 setRetainedInstance(true),您也可以将其用作后台工作线程,这是 Google 推荐的解决方案。我在 developer.android.com 某处读到 处理运行时更改developer.android.com/guide/topics/resources/… @AZ_ 是的,但是处理线程和处理数据是两件不同的事情。如果我有一些线程要处理,我会同意你的看法,但如果它只是原始数据,那么工厂模式就是要走的路。这也是谷歌根据他们自己的文档所做的方式:developer.android.com/guide/components/fragments.html 【参考方案1】:

那么用数据列表开始新片段的好方法是什么。

使用工厂模式和“参数”Bundle,如:

package com.commonsware.empublite;

import android.os.Bundle;

public class SimpleContentFragment extends AbstractContentFragment 
  private static final String KEY_FILE="file";

  protected static SimpleContentFragment newInstance(String file) 
    SimpleContentFragment f=new SimpleContentFragment();

    Bundle args=new Bundle();

    args.putString(KEY_FILE, file);
    f.setArguments(args);

    return(f);
  

  @Override
  String getPage() 
    return(getArguments().getString(KEY_FILE));
  

如果你保留你的片段实例,你应该能够只使用普通的 setter 将东西放入数据成员中。 “参数”Bundle 作为配置更改的一部分保留,因此对于非保留实例,这是确保在用户旋转屏幕等时保留设置数据的方法。

【讨论】:

@Warpzit:您的控制器(片段)从模型(数据库、ContentProvider、POJO 等)中检索数据并更新视图。在您编辑的问题中,我无法判断这是 B 还是 C。 @Warpzit:是的,片段将从托管活动接收到任何识别信息,它需要知道从模型中获取什么。其中一些可能会在创建时提供。如果存在可能在现有片段中更新该数据的情况,那么setRetainInstance() 开始真正派上用场... :-) setRetainInstance() 用于所有配置更改。不止是方向。 @CommonsWare 我不认为这个答案是完整的:文件名是否指向数据列表实际序列化的文件?是用于检索此列表的工厂模式。在当前代码中,我只看到了 Singleton 的实现。也许答案的建议是保留单个片段实例,然后使用设置器获取附加数据? @BorisStrandjev:“如果不使用 setter,您如何在保留实例方法中交换数据?” -- 将它传递给工厂方法(newInstance()),然后可以将数据提供给实例。需要明确的是,在我之前的回复中,我的真正意思是“公共二传手”。 “如果你可以控制它的类型声明,你对把它做成 Parcelable/Serializable 有什么看法?” ——总的来说,我尽量避免这样做。如果您还有其他疑虑,请提出一个新的 SO 问题,而不是在旧答案上扩展评论链。

以上是关于将初始数据提供给片段的正确方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何在主活动中正确检索片段中的视图

MPEG DASH 部分片段

Android:将片段和弹出窗口的点击事件中生成的变量传递给活动的方法

从片段访问父活动的数据

Kotlin - 如何将空值传递给片段 newInstance 方法?

在一些片段之间填充对象变量的最佳方法