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

时间:2014-10-14 10:05:08

标签: android android-fragments android-viewpager

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

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

Setter / Getters:我在几篇帖子中读过人们说不要使用二传手/吸气剂(我还没理解原因)Are getters and setters poor design? Contradictory advice seen

捆绑:我还没考虑过这个。由于我在这里再次感到困惑,我将如何使用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));
    }
    }

1st Fragment(这里我试图使用onPause()中的接口传递数据 - &gt;

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

    }

}

第二片段 - &gt;

   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 个答案:

答案 0 :(得分:8)

好的,我在ViewPager的两个标签之间传递数据(不仅仅是字符串)也有同样的问题。所以这就是我所做的。 我使用接口在不同组件之间进行通信。

数据以这种方式通过:

Tab 1 -> Activity -> VewPageAdapter -> Tab 2
  1. 在标签1中
  2. 创建一个界面。

    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. 活动
    2. 实现界面并覆盖方法

      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中

      还实现接口并覆盖方法

      @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
      2. 还实现接口并覆盖方法

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

答案 1 :(得分:1)

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

Read here how to

答案 2 :(得分:0)

你能做这样的事吗?首先在主要活动中创建任何数据结构,如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 - &gt;

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

    }

}

1st Fragment =&gt;

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

请注意,这可能无法编译。尝试获得这个概念。