提问者:小点点

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


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

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

Setter/Getters:我在一些帖子中读到过人们说不要使用setter/getter(我还没有明白原因)getter和setter的设计很差吗?看到了矛盾的建议

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

对不起,如果我的问题听起来很愚蠢。我正在努力理解片段,我想知道在viewpager中片段之间传递数据的最佳方法。事先谢谢你。

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));
    }
    }

第一个片段(这里我试图使用onP不()中的接口传递数据--

    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);
                    }
                });
            }
        }

    }

}

第二部分

   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();
        }
    }


}

在我的第三个片段中,我试图得到这个值

         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));
        }


    }

共3个答案

匿名用户

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

数据以这种方式传递:

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

创建一个界面。

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

实现接口并覆盖方法

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.INViewPagerAdapter

同时实现接口并覆盖方法

@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");
    }
} 

同时实现接口并覆盖方法

@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());
        }
    }
}

匿名用户

从AndroidX开始,您可以创建ViewModel并在Activity和ViewPager中的所有片段之间共享数据

在这里阅读如何

匿名用户

你能做这样的事情吗?首先在你的主活动中创建任何像Arraylist这样的数据结构。然后将该数据模型的引用发送到你的片段。现在在更改文本字段时更新该数据。通过这样做,所有片段都可以看到更新的值。因此片段可以更新此数据本身,我们不需要发送该数据,因为它已经共享。我将使用您的示例来解释这一点。尝试改进这一点。您可以维护特定于片段的数据模型,然后每个片段都可以在该数据所有者的知识下访问数据。

TabsPagerAdapter.java

public class TabsPagerAdapter extends FragmentPagerAdapter {

    public TabsPagerAdapter(FragmentManager fm,SubmitPostActivity activity){
        super(fm);
    }


    @Override
       public Fragment getItem(int index) {

       switch(index) {

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

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

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

        }
        return null;
    }

    @Override
    public int getCount() {       
       return 3;
    }

}

ViewPagerActivity--

package com.jbandroid;

public class SubmitPostActivity extends FragmentActivity implements ActionBar.TabListener,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" };
    public List<String> dataModel = new ArrayList<String>();


    @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(),this);
        //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));
        }

    }

}

第一个片段=

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 int position;
    private Resources res;

    SubmitPostActivity callingActivity;
    List<String> post_details;

    public PostInfoFragment(int position,SubmitPostActivity callingActivity )
    {
        this.callingActivity = callingActivity;
        this.position = position;
    }

    //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");

        //this is editText onchange listner do the same for submit_post_desc as well
        submit_post_title.addTextChangedListener( new TextWatcher()
        {

            @Override
            public void onTextChanged( CharSequence s, int start, int before, int count )
            {

            }

            @Override
            public void beforeTextChanged( CharSequence s, int start, int count, int after )
            {
            }

            @Override
            public void afterTextChanged( Editable s )
            {
                if( callingActivity != null )
                {
                //use this.position in order to update relevant data 
                    List<String> post_details = callingActivity.dataModel;
                    if( post_details == null )
                    {
                        post_details = new ArrayList<String>();
                    }
                    post_details.add(s.toString());
                }
            }
        } );


        return rootView;

    }

    //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 {
            callingActivity = (SubmitPostActivity) activity;
        } catch (ClassCastException e) {

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

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

请不要认为这可能无法按原样编译。尝试了解概念。