如何在ViewPager中的Fragment之间传递数据?

5

这里有一个TabLayout和ViewPager,我想要从Fragment1传递数据到Fragment2。

注意:Fragment1和Fragment2位于ViewPager中,因此无法按照正常的方式传递数据。

FragmentTransaction fragmentTx=this.FragmentManager.BeginTransaction();
            TracksByGenres fragTrack=new TracksByGenres();
            fragTrack.AddData(items[e.Position]);
            //get our item from listview

            fragmentTx.Replace(Resource.Id.fragmentContainer,fragTrack);    
            fragmentTx.AddToBackStack(null);
            fragmentTx.Commit();

你可以使用基于事件的解决方案,我在一个ViewPager中有2个片段并成功传递了数据。去搜索EventBus吧。如果你想要,我可以给你一个可工作的示例。 - Yasin Kaçmaz
6个回答

7
使用sharedPreferences
SharedPreferences sharedpreferences;
public static final String MyPREFERENCES = "MyPrefs" ;
sharedpreferences = getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE);

保存数值

SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString("TAG_NAME", "value");
editor.commit();

从偏好设置中检索数据:在第二个片段中

public static final String MyPREFERENCES = "MyPrefs" ;
SharedPreferences prefs = getSharedPreferences(MyPREFERENCES , MODE_PRIVATE); 
String restoredText = prefs.getString("TAG_NAME", null);

2
不建议使用 - Manoj Reddy

5

这是一个旧问题,所有上面的答案都是有效的。现在是2019年,自从Android Architecture Components以来,Android已经发生了很多变化。

enter image description here

如果您正在使用Android JetPack,则可以在宿主Activity类上添加观察器,以监听Fragment类中的Live Data变化。
创建一个单例repo来持有live data。
/**
 * Data Class Live Data
 */
class Repository private constructor() {


    private var currentProgress: MutableLiveData<Float> = MutableLiveData()

    fun getLiveProgress(): MutableLiveData<Float> {
        return currentProgress
    }

    companion object {

        private val mInstance: Repository =
                Repository()

        @Synchronized
        fun getInstance(): Repository {
            return mInstance
        }
    }
}

在 Activity 或 Fragment 类中的任何位置设置实时数据

  viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
            override fun onPageScrollStateChanged(state: Int) {
            }

            override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
                headMotionScene.progress = positionOffset
                Repository.getInstance().getLiveProgress().value = positionOffset
            }

            override fun onPageSelected(position: Int) {
            }

        })

从您的Fragment/Service类中观察数据变化
    Repository.getInstance().getLiveProgress().observe(this, Observer<Float> {
        motionLayout.progress = it
    })

如果您是LiveData的新手,请查看此示例以更好地理解:https://androidwave.com/fragment-communication-using-viewmodel/ - Bhavin Patel

4
你可以使用一个接口。
public interface DataBoy{
    public void bigDog(Data data);
}

片段1内部:

DataBoy dataBoy = (DataBoy)getActivity().getSupportFragmentManager().findFragmentById(R.id.fragment2);

dataBoy.bigDog(data);

在片段2内部:
fragment2 implements DataBoy {
...

@Override
public void bigDog(Data data);
doSomethingWith(data);
}

2

最好的方法是使用SharedPreferences

为此,我们需要像这样定义和初始化SharedPreferences

SharedPreferences preferences;
public static final String MY_SHARED_PREFERENCES = "MySharedPrefs" ;
preferences = getSharedPreferences(MY_SHARED_PREFERENCES, Context.MODE_PRIVATE);

为了节省空间,使用以下代码。
SharedPreferences.Editor editor = preferences.edit();
editor.putString("YOUR_TAG_NAME", "value");
editor.commit();

要从第二个片段的SharedPreferences中检索数据,请使用以下代码

public static final String MY_SHARED_PREFERENCES = "MySharedPrefs" ;
SharedPreferences myPreferences = getSharedPreferences(MY_SHARED_PREFERENCES , MODE_PRIVATE); 
String restoredText = myPreferences.getString("YOUR_TAG_NAME", null);

或者

您还可以使用以下方法在片段之间传递数据,但这种方法有点繁琐,并且只在您需要在viewpager内的另一个片段中传输大量数据时才有帮助。

要将数据从第1个片段(假设为FirstFragment)传递到Viewpager内的第2个片段(假设为SecondFragment),请按照以下步骤操作。

步骤1:创建一个接口,其方法签名如下。

public interface ShareIt {
    public void passIt(String data);
}

步骤2:SecondFragment需要实现ShareIt接口并重写passIt方法,并且您需要将传递自FirstFragment的数据存储在本地变量中。除此之外,我还会传递Viewpager的实例和Fragment的索引。 Viewpager的实例是findFragmentByTag方法所必需的参数。 因此,您的SecondFragment应如下所示。

public class SecondFragment extends Fragment implements ShareIt {

private NonSwipeableViewPager pager;
private int index;
private String string;

public static SecondFragment newInstance(int index, NonSwipeableViewPager viewPager) {
    SecondFragment f = new SecondFragment();
    Bundle args = new Bundle();
    args.putSerializable("VP", viewPager);
    args.putInt("index", index);
    f.setArguments(args);
    return f;
}


@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_second, container, false);

    Bundle bundle = getArguments();
    pager = (NonSwipeableViewPager) bundle.getSerializable("VP");
    index = bundle.getInt("index");



    return rootView;
}

@Override
public void passIt(String data) {
    string = data; // Storing the data which is been passed from FirstFargment in a local variable
    Toast.makeText(getActivity(), "" + data, Toast.LENGTH_SHORT).show();
 }
}

步骤三:现在我们需要在Viewpager中找到SecondFragment,就像这样:

Fragment frag = getActivity().getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + pager.getCurrentItem()); 
// pager.getCurrentItem() will give 0, index 0 will have instance of FirstFragment, but we want instance of SecondFragment, so we need to pass 1 instead of pager.getCurrentItem()
Fragment frag = getActivity().getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + 1); 

我们已经获取了SecondFragment的实例,可以通过调用SecondFragment的passIt方法来传递数据,如下所示:

((SecondFragment)dataBoy).passIt("Hello..!!!!");

因此,你的FirstFragment将会像这样。

public class FirstFragment extends Fragment {

private Button btnNext;

private NonSwipeableViewPager pager;
private int index;




public static FirstFragment newInstance(int index, NonSwipeableViewPager viewPager) {
    FirstFragment f = new FirstFragment();
    Bundle args = new Bundle();
    args.putSerializable("VP", viewPager);
    args.putInt("index", index);
    f.setArguments(args);
    return f;
}


@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_first, container, false);
    Bundle bundle = getArguments();
    pager = (NonSwipeableViewPager) bundle.getSerializable("VP");
    index = bundle.getInt("index");
    btnNext = findViewById(R.id.btnNext);
    Fragment frag= getActivity().getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + 1);




    btnNext.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            ((SecondFragment)frag).passIt("Hello..!!!!");           

        }
    });


    return rootView;
  }

}

0

取决于数据的性质。

理想情况下,数据应该保存在ActivityViewPager Adapter中-因此,每个Fragment在构建时都从Activity等获取其数据。请参见这个SO上的问题

我认为最好的解决方案是,如果您可以将数据存储在数据库中,则每个Fragment通过CotnentProvider将数据存储在数据库中,然后您可以使用Loaders特别是CursorLoader来检索数据-这种方法将始终为您提供最新的数据,因为当数据发生更改时,Laoder将被通知。

在这里查看官方文档示例

除了原始类型等设置之外,我不建议使用上面建议的首选项来存储复杂数据。


@Zain 谢谢你的更新! - Steve C.

0

尝试使用以下代码在片段之间传递数据

Bundle bundle = new Bundle();
FragmentTransaction fragmentTx=this.FragmentManager.BeginTransaction();
TracksByGenres fragTrack=new TracksByGenres();
bundle.putString(key, value); i.e bundle.putString("myKey",items[e.Position]);
fragTrack.setArguments(bundle);
                //get our item from listview
fragmentTx.Replace(Resource.Id.fragmentContainer,fragTrack);    
fragmentTx.AddToBackStack(null);
fragmentTx.Commit();

通过调用片段 onCreate() 来检索数据

Bundle bundle = this.getArguments();
String value= bundle.putString(key, defaultValue); i.e bundle.putString(myKey, "");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接