Android:在 viewpager fragment 之间传递数据的最佳方法

标签 android android-fragments android-viewpager

我在 ViewPager Activity 中有 3 个 fragment 。所有 3 个 fragment 都有输入字段。在这里,我试图将前两个 fragment 数据传递给第三个 fragment 。我在这里读了几篇文章,其中大多数建议使用接口(interface)(即通过父 Activity 传递数据) 我也通过了这个链接 http://developer.android.com/training/basics/fragments/communicating.html

接口(interface):当我们通过某些用户事件发送数据时,使用接口(interface)是一种很好的方法。在这里,我试图在没有任何用户事件的情况下发送数据。因此我想到了 onPause() 因为 onPause() 总是被调用。但是 ViewPager 的功能不同。加载一个 fragment 时,也会加载相邻的 fragment 。我会成功地在第一个 fragment 和第三个 fragment 之间传递数据。但是第二个 fragment 的 onPause() 不会被调用,除非我导航到一些不相邻的 fragment (在我的例子中不存在)

Setter/Getters:我在一些帖子中看到有人说不要使用setter/getters(我还没有明白原因)Are getters and setters poor design? Contradictory advice seen

bundle :我还没有考虑过这个。由于我在这里再次感到困惑,我将如何使用 bundle 传递数据。(我应该在哪个方法中发送数据?以及如何发送数据?)

抱歉,如果我的问题听起来很愚蠢。我正在尝试理解 fragment ,我想知道在 viewpager 中的 fragment 之间传递数据的最佳方式。 提前谢谢你。

TabPAgerAdapter -->

  package com.jbandroid.model;

import com.jbandroid.fragment.LocationInfoFragment;
import com.jbandroid.fragment.PersonalInfoFragment;
import com.jbandroid.fragment.PostInfoFragment;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public class TabsPagerAdapter extends FragmentPagerAdapter {

    public TabsPagerAdapter(FragmentManager fm){
        super(fm);
    }


    @Override
    public Fragment getItem(int index) {

        switch(index) {

        case 0 : //PostInfoFragment
                         return new PostInfoFragment();

        case 1 : //LocationInfoFragment
                        return new LocationInfoFragment();

        case 2 : //PersonalInfoFragment
                         return new PersonalInfoFragment();

        }

        return null;
    }

    @Override
    public int getCount() {
        // get item count - equal to number of tabs
        return 3;
    }

}

ViewPagerActivity -->

 package com.jbandroid;

public class SubmitPostActivity extends FragmentActivity implements ActionBar.TabListener,PostInfoFragment.setPostInfo,LocationInfoFragment.setLocationInfo{

    private ViewPager viewpager;
    private ActionBar actionBar;
    private TabsPagerAdapter mAdapter;
     FragmentManager manager;
     PersonalInfoFragment frag;
     List<String> location;
    /*private MenuItem myActionMenuItem;
      private Button myActionButton;*/


    //Tab titles
    private String[] tabs  = {"Post Info" , "Location Info" , "Personal Info" };



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.action_submit_post);

        viewpager = (ViewPager) findViewById(R.id.pager);
        actionBar = getActionBar();
        manager = getSupportFragmentManager();
        mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
        //viewpager.setOffscreenPageLimit(2);
        viewpager.setAdapter(mAdapter);

        //actionBar.setHomeButtonEnabled(false);
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        for (String tab : tabs){
            actionBar.addTab(actionBar.newTab().setText(tab).setTabListener(this));
        }

        if(savedInstanceState != null){
            actionBar.setSelectedNavigationItem( savedInstanceState.getInt("tab",0));
        }

        /**
         * on swiping the viewpager make respective tab selected
         * */

        viewpager.setOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageSelected(int position) {
                // on changing the page
                // make respected tab selected
                actionBar.setSelectedNavigationItem(position);
            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {

            }

            @Override
            public void onPageScrollStateChanged(int arg0) {

            }
        });
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
    }



    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {

    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        // on tab selected
        // show respected fragment view

        viewpager.setCurrentItem(tab.getPosition());

    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {

    }



    @Override
    public void pass_location_details(List<String> location) {

         frag = (PersonalInfoFragment) manager.findFragmentByTag("android:switcher:" + viewpager.getId() + ":" + 2);
        frag.get_post_location_details(location);
        Log.d("submitarea", location.get(0));
    }


    @Override
    public void pass_post_details(List<String> post_details,ArrayList<CustomGallery> selected) {
         frag = (PersonalInfoFragment) manager.findFragmentByTag("android:switcher:" + viewpager.getId() + ":" + 2);
            frag.get_post_details(post_details,selected);
            Log.d("submitpostinfo","hello"+ post_details.get(5));
    }
    }

第一个 fragment (这里我尝试使用 onPause() 中的接口(interface)传递数据-->

    package com.jbandroid.fragment;
public class PostInfoFragment extends Fragment {

    private MenuItem myActionMenuItem;
    private Button myActionButton;
    private ActionBar actionBar;
    private String post_title, post_desc,post_status;

    private EditText submit_post_title, submit_post_desc;

        private Resources res;

    setPostInfo info;
    List<String> post_details;


    //RelativeLayout rel_submit_post_start_date,rel_submit_post_end_date;

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

        /*if(!imageLoader.isInited()){*/
        initImageLoader();
        /*}*/

        //handler = new Handler();


        submit_post_title = (EditText) rootView
                .findViewById(R.id.submit_post_title);
        submit_post_desc = (EditText) rootView
                .findViewById(R.id.submit_post_description);

        actionBar = getActivity().getActionBar();
        setHasOptionsMenu(true);

        post_details = new ArrayList<String>();
        res = getResources();

        setListeners();

        Log.d("postinfo_oncreate view", "postinfo_oncreate view");

        return rootView;

    }



    //interface to pass data to activity and then to PersonalInfoFragment
    public interface setPostInfo {
        //public void pass_post_details(List<String> post_details);
        public void pass_post_details(List<String> post_details,ArrayList<CustomGallery> selected);
    }


    //making sure if the parent activity has implemented interface
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            info = (setPostInfo) activity;
        } catch (ClassCastException e) {

            throw new ClassCastException(activity.toString()
                    + "must implemet setPostInfo");
        }

         Log.d("postinfo_onattach", "postinfo_onattach");
    }


    //passing form inputs to personalinfofragments
    @Override
    public void onPause() {
        super.onPause();
        // setFormInputs();

        passFormInputs();  ---> passing in onPause() This executes successfully

         Log.d("postinfo_onPAuse", "postinfo_onPause");

    }


    //method to pass data to personalinfofragment
    private void passFormInputs() {
        try {
            post_title = submit_post_title.getText().toString();
            post_desc = submit_post_desc.getText().toString();
            post_status = "1";

            if(post_title != null && post_title.length() > 0 

                    && post_desc != null && post_desc.length() > 0
                    && post_status != null && post_status.length() > 0
                    ){
            post_details.add(post_title);
            post_details.add(post_desc);
            post_details.add(post_status);

            info.pass_post_details(post_details,dataT); -->here I am passing values via             
            }else{                                                activity to 3rd fragment
                Log.d("post_info", "values are null");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    //setting next button on actionbar
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);

        // Inflate the menu items for use in the action bar

        inflater.inflate(R.menu.mymenu, menu);

        // Here we get the action view we defined
        myActionMenuItem = menu.findItem(R.id.my_action);
        View actionView = myActionMenuItem.getActionView();

        // We then get the button view that is part of the action view
        if (actionView != null) {
            myActionButton = (Button) actionView.findViewById(R.id.action_btn);
            myActionButton.setText(R.string.txt_next);
            if (myActionButton != null) {
                // We set a listener that will be called when the return/enter
                // key is pressed
                myActionButton.setOnClickListener(new OnClickListener() {

                    @Override
                    public void onClick(View v) {

                        actionBar.setSelectedNavigationItem(1);
                    }
                });
            }
        }

    }

}

第二个 fragment -->

   package com.jbandroid.fragment;



public class LocationInfoFragment extends Fragment implements OnClickListener {

    private MenuItem myActionMenuItem;
    private Button myActionButton;
    private ActionBar actionBar;

    Dialog dialog;
    private EditText submit_post_exact_location;
    private TextView selected_country, selected_city, 
            submit_post_exact_time;
    String country, city, exact_location, exact_time;
    setLocationInfo info;

    List<String> location;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.fragment_location_info,
                container, false);
        actionBar = getActivity().getActionBar();
        setHasOptionsMenu(true);


        submit_post_exact_location = (EditText) rootView
                .findViewById(R.id.submit_post_exact_location);
        submit_post_exact_time = (TextView) rootView
                .findViewById(R.id.submit_post_exact_time);

        selected_country = (TextView) rootView
                .findViewById(R.id.selected_country);
        selected_city = (TextView) rootView.findViewById(R.id.selected_city);



        location = new ArrayList<String>();
        setListeners();

        return rootView;

    }

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);

        // Inflate the menu items for use in the action bar

        inflater.inflate(R.menu.mymenu, menu);

        // Here we get the action view we defined
        myActionMenuItem = menu.findItem(R.id.my_action);
        View actionView = myActionMenuItem.getActionView();

        // We then get the button view that is part of the action view
        if (actionView != null) {
            myActionButton = (Button) actionView.findViewById(R.id.action_btn);
            myActionButton.setText(R.string.txt_next);
            if (myActionButton != null) {
                // We set a listener that will be called when the return/enter
                // key is pressed
                myActionButton.setOnClickListener(new OnClickListener() {

                    @Override
                    public void onClick(View v) {


                        actionBar.setSelectedNavigationItem(2);

                    }
                });
            }
        }
    }


    public interface setLocationInfo {
        public void pass_location_details(List<String> location);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            info = (setLocationInfo) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + "must implement setLocationInfo");
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        //setLocationDetails();
    }

    @Override
    public void onPause() {
        super.onPause();
         setLocationDetails();   ----> doesnt executes since onPause isnt called when I                                      navigate to 3rd fragment as it is an adjacent fragment of this fragment
        // Log.d("location : onPause", area);
    }

    private void setLocationDetails() {
        try {

            exact_location = submit_post_exact_location.getText().toString();
            exact_time = submit_post_exact_time.getText().toString();
country = selected_country.getText().toString();
city =  selected_city.getText().toString();

            if (country != null && country.length() > 0
                    && !country.equalsIgnoreCase("select") && city != null
                    && city.length() > 0 && !city.equalsIgnoreCase("select")

                    && exact_location != null && exact_location.length() > 0
                    && exact_time != null && exact_time.length() > 0) {

                location.add(country);
                location.add(city);

                location.add(exact_location);
                location.add(exact_time);
                info.pass_location_details(location);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

在我的第三个 fragment 中,我试图获得这个值

         public class PersonalInfoFragment extends Fragment {
    List<String> post_details;
    List<String> location;
    Button submit;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_personal_info,
                    container, false);
    submit = (Button)rootView.findViewById(R.id.submitBtn);
    submit.setOnClickListener(new OnClickListener() {

                        @Override
                        public void onClick(View v) {

                            //performing operations with the values obtained
                            setPostItems();

                            insertintodb();


                        }
                    });

    return rootView;
    }

    public void get_post_details(List<String> post_details,
                ArrayList<CustomGallery> selected) {            -->receiving values from
            this.post_details = post_details;                         1st fragment
            this.selected = selected;
            Log.d("personalfrag(postinfo)", "hello" + post_details.get(5));
        }


//receiving values from 2nd fragment
        public void get_post_location_details(List<String> location) {
            this.location = location;
            Log.d("personalfrag(locationinfo)", "hello" + location.get(0));
        }


    }

最佳答案

好的,我在 ViewPager 的两个选项卡之间传递数据(不仅仅是字符串)时遇到了同样的问题。所以这就是我所做的。 我使用接口(interface)在不同组件之间进行通信。

数据以这种方式传递:

Tab 1 -> Activity -> VewPageAdapter -> Tab 2
  1. 在选项卡 1 中

创建一个接口(interface)。

OnCartsDataListener mOncarOnCartsDataListener;


public interface OnCartsDataListener {

    public void onCartsDataReceived(ArrayList<CartsViewModel> cartsViewModels);

}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
        mOncarOnCartsDataListener = (OnCartsDataListener)activity;
    }catch (ClassCastException e){

    }

}
// now call mOncarOnCartsDataListener.onCartsDataReceived(data) when you have the data
  1. Activity 中

实现接口(interface)并覆盖方法

ViewPagerAdapter adapter;
adapter = new ViewPagerAdapter(getSupportFragmentManager(), Titles, Numboftabs);

@Override
public void onCartsDataReceived(ArrayList<CartsViewModel> cartsViewModels) {
    Log.d(TAG, "data received to Activity... send to view pager");
    adapter.onCartsDataReceived(cartsViewModels);
}

3.在ViewPagerAdapter中

同时实现了接口(interface)并重写了方法

@Override
public void onCartsDataReceived(ArrayList<CartsViewModel> cartsViewModels) {
    Log.d(TAG, "data received to view pager... sending to tab 2");

    if(tab2!=null){
        tab2.onCartsDataReceived(cartsViewModels);
    }else{
        Log.d(TAG, "tab2 is null");
    }
} 
  1. 最后是选项卡 2

也实现了接口(interface)并覆盖了方法

@Override
public void onCartsDataReceived(ArrayList<CartsViewModel> cartsViewModels) {
    Log.d(TAG, "Finally ! received data to tab 2");
    if(cartsViewModels!=null){
        for(CartsViewModel cart : cartsViewModels){
            Log.d(TAG,"got it :"+cart.getCartName());
        }
    }
}

关于Android:在 viewpager fragment 之间传递数据的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26358043/

相关文章:

java - 如何在 Android Espresso 中的 View 之间导航

android - 当音频插孔连接或忙碌时在 fragment 内切换图像

android - 什么时候更新 ViewPager 的信息?

android-studio - Kotlin AddOnPageChangeListener 不起作用

android - 防止 EditText 在软键盘的“下一步”按钮单击上获得焦点

android - OBEX OPP 特定传输

android - 在背景边框的左上角带有提示的圆角矩形背景编辑文本

android - Home Fragment 部分可见,当前 Fragment Android Studio 的混合 View

android - 如何在 ActionBar 中引入 Swipeable Tabs?

java - 查看页面 : Refresh fragment views on user swipe