I'm using a template to build a tabbed app which employs a custom class (that extends Fragment) and
how can I pass values from the first fragment to the second one?

Description: In a package three classes control the creation of tabs and views:

Tabs: package com.research.fragmenttabstudy.base;

public class AppConstants {
       public static final String TAB_A  = "tab_a_identifier";
       public static final String TAB_B  = "tab_b_identifier";

       //Your other constants, if you have them..

}

Fragments:

package com.research.fragmenttabstudy.base;

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;

public class BaseFragment extends Fragment {
    public AppMainTabActivity mActivity;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mActivity       =   (AppMainTabActivity) this.getActivity();
    }

    public boolean onBackPressed(){
        return false;
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data){

    }
}

And the mainActivity:

package com.research.fragmenttabstudy.base;

import java.util.HashMap;
import java.util.Stack;

import com.research.fragmenttabstudy.R;
import com.research.fragmenttabstudy.tabA.AppTabAFirstFragment;
import com.research.fragmenttabstudy.tabB.AppTabBFirstFragment;

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TabHost;

public class AppMainTabActivity extends FragmentActivity {
    /* Your Tab host */
    private TabHost mTabHost;

    /* A HashMap of stacks, where we use tab identifier as keys..*/
    private HashMap<String, Stack<Fragment>> mStacks;

    /*Save current tabs identifier in this..*/
    private String mCurrentTab;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.app_main_tab_fragment_layout);

        /*  
         *  Navigation stacks for each tab gets created.. 
         *  tab identifier is used as key to get respective stack for each tab
         */
        mStacks             =   new HashMap<String, Stack<Fragment>>();
        mStacks.put(AppConstants.TAB_A, new Stack<Fragment>());
        mStacks.put(AppConstants.TAB_B, new Stack<Fragment>());

        mTabHost                =   (TabHost)findViewById(android.R.id.tabhost);
        mTabHost.setOnTabChangedListener(listener);
        mTabHost.setup();

        initializeTabs();



//Receive intent from Fragment AppTabBFirstFragment
        Intent intent = getIntent();
        String url = intent.getStringExtra("URLone");

        //Send data to AppTabBSecondFragment
        Bundle bundle=new Bundle();
        bundle.putString("urlToSecond", url);
        AppTabBSecondFragment objFragment = new AppTabBSecondFragment();
        objFragment.setArguments(bundle);        }


    private View createTabView(final int id) {
        View view = LayoutInflater.from(this).inflate(R.layout.tabs_icon, null);
        ImageView imageView =   (ImageView) view.findViewById(R.id.tab_icon);
        imageView.setImageDrawable(getResources().getDrawable(id));
        return view;
    }

    public void initializeTabs(){
        /* Setup your tab icons and content views.. Nothing special in this..*/
        TabHost.TabSpec spec    =   mTabHost.newTabSpec(AppConstants.TAB_A);
        mTabHost.setCurrentTab(-3);
        spec.setContent(new TabHost.TabContentFactory() {
            public View createTabContent(String tag) {
                return findViewById(R.id.realtabcontent);
            }
        });
        spec.setIndicator(createTabView(R.drawable.tab_a_state_btn));
        mTabHost.addTab(spec);


        spec                    =   mTabHost.newTabSpec(AppConstants.TAB_B);
        spec.setContent(new TabHost.TabContentFactory() {
            public View createTabContent(String tag) {
                return findViewById(R.id.realtabcontent);
            }
        });
        spec.setIndicator(createTabView(R.drawable.tab_b_state_btn));
        mTabHost.addTab(spec);
    }


    /*Comes here when user switch tab, or we do programmatically*/
    TabHost.OnTabChangeListener listener    =   new TabHost.OnTabChangeListener() {
      public void onTabChanged(String tabId) {
        /*Set current tab..*/
        mCurrentTab                     =   tabId;

        if(mStacks.get(tabId).size() == 0){
          /*
           *    First time this tab is selected. So add first fragment of that tab.
           *    Dont need animation, so that argument is false.
           *    We are adding a new fragment which is not present in stack. So add to stack is true.
           */
          if(tabId.equals(AppConstants.TAB_A)){
            pushFragments(tabId, new AppTabAFirstFragment(), false,true);
          }else if(tabId.equals(AppConstants.TAB_B)){
            pushFragments(tabId, new AppTabBFirstFragment(), false,true);
          }
        }else {
          /*
           *    We are switching tabs, and target tab is already has atleast one fragment. 
           *    No need of animation, no need of stack pushing. Just show the target fragment
           */
          pushFragments(tabId, mStacks.get(tabId).lastElement(), false,false);
        }
      }
    };


    /* Might be useful if we want to switch tab programmatically, from inside any of the fragment.*/
    public void setCurrentTab(int val){
          mTabHost.setCurrentTab(val);
    }


    /* 
     *      To add fragment to a tab. 
     *  tag             ->  Tab identifier
     *  fragment        ->  Fragment to show, in tab identified by tag
     *  shouldAnimate   ->  should animate transaction. false when we switch tabs, or adding first fragment to a tab
     *                      true when when we are pushing more fragment into navigation stack. 
     *  shouldAdd       ->  Should add to fragment navigation stack (mStacks.get(tag)). false when we are switching tabs (except for the first time)
     *                      true in all other cases.
     */
    public void pushFragments(String tag, Fragment fragment,boolean shouldAnimate, boolean shouldAdd){
      if(shouldAdd)
          mStacks.get(tag).push(fragment);
      FragmentManager   manager         =   getSupportFragmentManager();
      FragmentTransaction ft            =   manager.beginTransaction();
      if(shouldAnimate)
          ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left);
      ft.replace(R.id.realtabcontent, fragment);
      ft.commit();
    }


    public void popFragments(){
      /*    
       *    Select the second last fragment in current tab's stack.. 
       *    which will be shown after the fragment transaction given below 
       */
      Fragment fragment             =   mStacks.get(mCurrentTab).elementAt(mStacks.get(mCurrentTab).size() - 2);

      /*pop current fragment from stack.. */
      mStacks.get(mCurrentTab).pop();

      /* We have the target fragment in hand.. Just show it.. Show a standard navigation animation*/
      FragmentManager   manager         =   getSupportFragmentManager();
      FragmentTransaction ft            =   manager.beginTransaction();
      ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);
      ft.replace(R.id.realtabcontent, fragment);
      ft.commit();
    }   


    @Override
    public void onBackPressed() {
        if(((BaseFragment)mStacks.get(mCurrentTab).lastElement()).onBackPressed() == false){
            /*
             * top fragment in current tab doesn't handles back press, we can do our thing, which is
             * 
             * if current tab has only one fragment in stack, ie first fragment is showing for this tab.
             *        finish the activity
             * else
             *        pop to previous fragment in stack for the same tab
             * 
             */
            if(mStacks.get(mCurrentTab).size() == 1){
                super.onBackPressed();  // or call finish..
            }else{
                popFragments();
            }
        }else{
            //do nothing.. fragment already handled back button press.
        }
    }


    /*
     *   Imagine if you wanted to get an image selected using ImagePicker intent to the fragment. Ofcourse I could have created a public function
     *  in that fragment, and called it from the activity. But couldn't resist myself.
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(mStacks.get(mCurrentTab).size() == 0){
            return;
        }

        /*Now current fragment on screen gets onActivityResult callback..*/
        mStacks.get(mCurrentTab).lastElement().onActivityResult(requestCode, resultCode, data);
    }
}

Now, a new package contains the classes associated to a tab, keeping this tab always visible:

package com.research.fragmenttabstudy.tabB;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

import com.research.fragmenttabstudy.R;
import com.research.fragmenttabstudy.base.AppConstants;
import com.research.fragmenttabstudy.base.BaseFragment;

public class AppTabBFirstFragment extends BaseFragment {
        private Button itemOne;
        String itemOneUrl = "http://url”;

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

        View view       =   inflater.inflate(R.layout.app_tab_b_first_screen, container, false);


        itemOne =   (Button) view.findViewById(R.id.itemOne);
        itemOne.setOnClickListener(listener);
                return view;
    }

    private OnClickListener listener        =   new View.OnClickListener(){
        @Override
        public void onClick(View v){
            // Go to next fragment in navigation stack


//Callback
    Intent intent = new Intent (getActivity().getBaseContext(), AppMainTabActivity.class);
    intent.putExtra("URLone", itemOneUrl);
    getActivity().startActivity(intent);

            mActivity.pushFragments(AppConstants.TAB_B, new AppTabBSecondFragment(),true,true);
        }
    };
 }

And here is the class for the second fragment:

package com.research.fragmenttabstudy.tabB;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.research.fragmenttabstudy.R;
import com.research.fragmenttabstudy.base.BaseFragment;

public class AppTabBSecondFragment extends BaseFragment {

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


        TextView tab = (TextView) view.findViewById(R.id.tab);
    String urlOne = getArguments().getString("urlToSecond");
    tab.setText(urlOne);


        return view;
    }
}
有帮助吗?

解决方案

You use callback interfaces to pass data from the Fragment to its Activity. The Activity then finds the Fragment to receive the data and (if the Fragment exists) calls a method in that Fragment to pass the data (or creates the Fragment if it doesn't exist yet).

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top