Pass data between tabs - android

I have a MainActivity (FragmentActivity) that has a FragmentTabHost.
public class FragmentTabs extends FragmentActivity {
private FragmentTabHost mTabHost;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_tabs);
mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
mTabHost.addTab(mTabHost.newTabSpec("classA").setIndicator("Class A"),
ClassA.class, null);
mTabHost.addTab(mTabHost.newTabSpec("classB").setIndicator("Class B"),
ClassB.class, null);
mTabHost.addTab(mTabHost.newTabSpec("classC").setIndicator("Class C"),
ClassC.class, null);
}
}
ClassA, ClassB and ClassC are all Fragments (android.support.v4.app.Fragment).
I need to pass data (and call methods) on the Fragments. How can I get a reference of each of the Fragments, like this:
ClassA mClassAFragment = ???;
I’ve tried using getSupportFragmentManager().findFragmentByTag() and I’ve also tried exploring the capabilities of mTabHost. Nothing can get them.
Can you suggest a way to do this or suggest an alternative approach?
And i tried used this...
Bundle arguments = new Bundle();
arguments.putString("some id string", "your data");
YourFragment fragment = new YourFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction().add(R.id.fragmentid, fragment).commit();
but i dont know how can use this R.id.fragmentid if my add tabs is well:
mTabHost.addTab(mTabHost.newTabSpec("classA").setIndicator("Class A"),
ClassA.class, null);
Anyone help me?

Define the Fragments in your Activity as public. Then in each Fragment you also reference the Activity.
In your Activity:
public ClassAFragment aFragment;
...
// during initialization:
aFragment = new ClassAFragment();
// or you get it from your TabHost
FragmentManager fm = getFragmentManager();
aFragment = fm.findFragmentByTag("ClassA");
aFragment.mActivity = this;
// same with B and C
In your Fragments:
public MainActivity mActivity;
...
// in Fragment C
String newText = mActivity.aFragment.editText.getText().toString() + mActivity.bFragment.editText.getText().toString();
textView.setText(newText);

Related

Passing parameters between tab fragments by using FragmentTabHost

I need to pass data between tab fragments after calling switch method of tabhost mTabHost.setCurrentTab(index);
public class FragmentTabs extends FragmentActivity {
private FragmentTabHost mTabHost;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_tabs);
mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.content);
mTabHost.addTab(mTabHost.newTabSpec("class1").setIndicator("Class 1"),
Class1.class, null);
mTabHost.addTab(mTabHost.newTabSpec("class2").setIndicator("Class 2"),
Class2.class, null);
mTabHost.addTab(mTabHost.newTabSpec("class3").setIndicator("Class C"),
Class3.class, null);
}
}
Is there any way to do that ?
Often you will want one Fragment to communicate with another, for example to change the content based on a user event. All Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly.
Check this: https://developer.android.com/training/basics/fragments/communicating.html

Create fragment and put it to TabHost?

I'm adding tabs to FragmentTabHost - mTabHost in my FragmentActivity:
mTabHost.addTab(mTabHost.newTabSpec("visit").setIndicator("Visit"), VisitTabFragment.class, bundle);
but I need a reference to my TabFragment. I found a partial solution, that I can set my
#Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
if (fragment instanceof VisitTabFragment)
visitTabFragment = (VisitTabFragment) fragment;
...
}
but it works only when I click on my tab. I tried also:
getSupportFragmentManager().findFragmentByTag(tag);
but it gaves me NullPointerException (probably it doesn't exists yet).
Is there a way to create fragment first and then add it to tabhost?
You should setup your tabhost before adding tabs to it:
mTabHost.setup(this, getSupportFragmentManager(), R.id.tabContent);
For reference can use sinleton pattern:
public class VisitTabFragment extends Fragment {
private static VisitTabFragment uniqInstance;
private VisitTabFragment() {
}
public static VisitTabFragment getInstance() {
if (uniqInstance == null) {
uniqInstance = new VisitTabFragment();
}
return uniqInstance;
}
.........
}
When you want to access your fragment should call:
VisitTabFragment.getInstance();
In your case call:
mTabHost.addTab(mTabHost.newTabSpec("visit").setIndicator("Visit"), VisitTabFragment.getInstance().getClass(), bundle);

Android FragmentTabHost how to get a reference to fragment in tab

I have a Fragment which implements FragmentTabHost and creates a couple of tabs each of which has a Fragment. I am trying to get a reference to one of these Fragments, but am drawing a blank as to how.
public class TabFragment extends Fragment {
private FragmentTabHost mTabHost;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mTabHost = new FragmentTabHost(getActivity());
mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.container);
addTab("study","Study",StudyFragment.class);
addTab("tab2","Tab 2",Tab2Fragment.class);
return mTabHost;
}
private <T extends Fragment> void addTab(String sTag, String sTitle, Class<T> c) {
View tabView = createTabView(getActivity(),sTitle);
mTabHost.addTab(mTabHost.newTabSpec(sTag).setIndicator(tabView),
c, null);
}
public StudyFragment getStudyFragment() {
// not working as fragment has not been tagged
return getChildFragmentManager().findFragmentByTag("study");
}
So the question is how do I either tag the study fragment or return a reference to it when it is created?
I've seen a couple of solutions which suggest overriding onAttachFragment, but that is for FragmentActivity not Fragment
To get a fragment, you can set an id to your fragment, then use this:
FragmentManager manager = getSupportFragmentManager();
MyFragment myFragment = (MyFragment)manager.findFragmentById(R.id.MyFragment);
Ok so you have to add tabs using TabHost.TabSpec like that:
tabHost = (FragmentTabHost)mainView.findViewById(android.R.id.tabhost);
tabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent);
TabHost.TabSpec tabOne = tabHost.newTabSpec("One").setContent(R.id.fragOne);
TabHost.TabSpec tabTwo = tabHost.newTabSpec("Two").setContent(R.id.fragTwo);
tabHost.addTab(tabOne, TabOne.class, savedInstanceState);
tabHost.addTab(tabTwo, TabTwo.class, savedInstanceState);
In this code R.id.fragOne and R.id.fragTwo refers to two FrameLayout defined in the activity layout.
If you dont have xml layout you can define programmatically a new FrameLayout with an id for each tab.

Replace a fragment in FragmentTabHost

I've implemented few Fragments in a FragmentTabHost, using:
Inside FragmentActivity Class:
FragmentTabHost mTabHost;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreateView()");
setContentView(R.layout.activity_main);
mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
mTabHost.addTab(mTabHost.newTabSpec("audio").setIndicator("Audio"),
AudioFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("video").setIndicator("Video"),
VideoFragment.class, null);
mTabHost.setOnTabChangedListener(this);
}
In one of the fragment say AudioFragment there is a button which is supposed to open a new fragment over the current fragment of AudioFragment.
Inside AudioFragment.class
#Override
public void onClick(View button) {
switch (button.getId()) {
case R.id.bOpenNewFragment:
// WHAT TO CODE, TO REPLACE THE CURRENT FRAGMENT OF AudioFragment
break;
}
}
I tried the usual code using:
Fragment fragment = new ShowAudioDetailsFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.realtabcontent, fragment);
transaction.addToBackStack(null);
transaction.commit();
But, it was creating problems when I switched to another tabs (like state was not maintained & view of new fragment was merging with the layout of other tabs).
So How can I replace the fragment with the fragment opened within FragmentTabHost
Thank You
Just add this line
((RelativeLayout) findViewById(R.id.realtabcontent)).removeAllViews(); // whatever layout you have
before :
transaction.replace(R.id.realtabcontent, fragment);

Passing an Object from an Activity to a Fragment

I have an Activity which uses a Fragment. I simply want to pass an object from this Activity to the Fragment.
How could I do it?
All the tutorials I've seen so far where retrieving data from resources.
EDIT :
Let's be a bit more precise:
My Activity has a ListView on the left part. When you click on it, the idea is to load a Fragment on the right part.
When I enter this Activity, an Object Category is given through the Intent. This Object contains a List of other Objects Questions (which contains a List of String). These Questions objects are displayed on the ListView.
When I click on one item from the ListView, I want to display the List of String into the Fragment (into a ListView).
To do that, I call the setContentView() from my Activity with a layout. In this layout is defined the Fragment with the correct class to call.
When I call this setContentView(), the onCreateView() of my Fragment is called but at this time, the getArguments() returns null.
How could I manage to have it filled before the call of onCreateView() ?
(tell me if I'm not clear enough)
Thanks
Create a static method in the Fragment and then get it using getArguments().
Example:
public class CommentsFragment extends Fragment {
private static final String DESCRIBABLE_KEY = "describable_key";
private Describable mDescribable;
public static CommentsFragment newInstance(Describable describable) {
CommentsFragment fragment = new CommentsFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(DESCRIBABLE_KEY, describable);
fragment.setArguments(bundle);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
mDescribable = (Describable) getArguments().getSerializable(
DESCRIBABLE_KEY);
// The rest of your code
}
You can afterwards call it from the Activity doing something like:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment fragment = CommentsFragment.newInstance(mDescribable);
ft.replace(R.id.comments_fragment, fragment);
ft.commit();
In your activity class:
public class BasicActivity extends Activity {
private ComplexObject co;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_page);
co=new ComplexObject();
getIntent().putExtra("complexObject", co);
FragmentManager fragmentManager = getFragmentManager();
Fragment1 f1 = new Fragment1();
fragmentManager.beginTransaction()
.replace(R.id.frameLayout, f1).commit();
}
Note: Your object should implement Serializable interface
Then in your fragment :
public class Fragment1 extends Fragment {
ComplexObject co;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Intent i = getActivity().getIntent();
co = (ComplexObject) i.getSerializableExtra("complexObject");
View view = inflater.inflate(R.layout.test_page, container, false);
TextView textView = (TextView) view.findViewById(R.id.DENEME);
textView.setText(co.getName());
return view;
}
}
You should create a method within your fragment that accepts the type of object you wish to pass into it. In this case i named it "setObject" (creative huh? :) ) That method can then perform whatever action you need with that object.
MyFragment fragment;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
fragment = new MyFragment();
getSupportFragmentManager().beginTransaction().add(android.R.id.content, detailsFragment)
.commit();
} else {
fragment = (MyFragment) getSupportFragmentManager().findFragmentById(
android.R.id.content);
}
fragment.setObject(yourObject); //create a method like this in your class "MyFragment"
}
Note that i'm using the support library and calls to getSupportFragmentManager() might be just getFragmentManager() for you depending on what you're working with
Get reference from the following example.
1. In fragment:
Create a reference variable for the class whose object you want in the fragment. Simply create a setter method for the reference variable and call the setter before replacing fragment from the activity.
MyEmployee myEmp;
public void setEmployee(MyEmployee myEmp)
{
this.myEmp = myEmp;
}
2. In activity:
//we need to pass object myEmp to fragment myFragment
MyEmployee myEmp = new MyEmployee();
MyFragment myFragment = new MyFragment();
myFragment.setEmployee(myEmp);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.main_layout, myFragment);
ft.commit();
Passing arguments by bundle is restricted to some data types. But you can transfer any data to your fragment this way:
In your fragment create a public method like this
public void passData(Context context, List<LexItem> list, int pos) {
mContext = context;
mLexItemList = list;
mIndex = pos;
}
and in your activity call passData() with all your needed data types after instantiating the fragment
WebViewFragment myFragment = new WebViewFragment();
myFragment.passData(getApplicationContext(), mLexItemList, index);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.my_fragment_container, myFragment);
ft.addToBackStack(null);
ft.commit();
Remark: My fragment extends "android.support.v4.app.Fragment", therefore I have to use "getSupportFragmentManager()". Of course, this principle will work also with a fragment class extending "Fragment", but then you have to use "getFragmentManager()".
To pass an object to a fragment, do the following:
First store the objects in Bundle, don't forget to put implements serializable in class.
CategoryRowFragment fragment = new CategoryRowFragment();
// pass arguments to fragment
Bundle bundle = new Bundle();
// event list we want to populate
bundle.putSerializable("eventsList", eventsList);
// the description of the row
bundle.putSerializable("categoryRow", categoryRow);
fragment.setArguments(bundle);
Then retrieve bundles in Fragment
// events that will be populated in this row
mEventsList = (ArrayList<Event>)getArguments().getSerializable("eventsList");
// description of events to be populated in this row
mCategoryRow = (CategoryRow)getArguments().getSerializable("categoryRow");
If the data should survive throughout the application lifecycle and shared among multiple fragments or activities, a Model class might come into consideration, which has got less serialization overhead.
Check this design example
This one worked for me:
In Activity:
User user;
public User getUser(){ return this.user;}
In Fragment's onCreateView method:
User user = ((MainActivity)getActivity()).getUser();
Replace the MainActivity with your Activity Name.

Categories

Resources