I have application which uses several fragments for showing different tabs.
The first fragment is List View with custom cell. Each cell has its own set of buttons. I want to show different fragment when a button is clicked. To know when the desired button is clicked I added an onclick event in the array adapter for my list. Is there a way to show the new fragment from Array Adapter. What I tried so far and it didn`t worked :
final FragmentManager fragmentManager = ((Activity)mContext)getSupportFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
PostFragment postFr = new PostFragment();
fragmentTransaction.replace(R.id.detail_container, postFr);
fragmentTransaction.commit();
try this code:
final FragmentManager fragmentManager = ((FragmentActivity)mContext).getSupportFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
PostFragment postFr = new PostFragment();
fragmentTransaction.replace(R.id.detail_container, postFr);
fragmentTransaction.commit();
getSupportFragmentManager() is only defined for the class FragmentActivity, not for Activity
what specifically went wrong when you tried to do that?
This is the method I use to go to a new fragment. I put it in an abstract BaseActivity class (extends AppCompatActivity) so that all of my implementing activities have use of the method.
The method takes the fragment you want to go to, and a boolean variable to indicate whether or not to add the transaction to the backstack.
The activity must have a FrameLayout declared in its XML resource file, with an id of "container". This is where the fragments will be placed.
public void gotoFragment(Fragment fragment, boolean addToBackStack) {
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment);
if (addToBackStack) {
transaction.addToBackStack(null);
}
transaction.commit();
}
In order to call this method from your ArrayAdapter class, pass an instance of the BaseActivity into the constructor of your Adapter.
For the Context parameter of the adapter, pass getActivity() from the fragment.
If all of your activity classes extend the BaseActivity class, you can safely say in your adapter:
public class CustomArrayAdapter extends ArrayAdapter {
private BaseActivity mActivity;
public CustomArrayAdapter(Context pContext, int pLayoutResource, List<Object> pItems) {
super(pContext, pLayoutResource);
mActivity = (BaseActivity) pContext;
}
#Override
public void onItemClick(int position) {
if (mActivity != null) {
mActivity.goToFragment(new PostFragment());
}
}
Related
What Structure I am having:
I Have a Activity called MainActivity.java
Inside MainActivity.java there is ParentFragment.java
Now inside ParentFragment.java there is ChildFragment.Java
Now inside ChildFragment.Java there is a adapter for it
ChildAdapter.java
Inside ChildAdapter.java the is a method called MyMethod()
Now How to access the MyMethod() in MainActivity.java
Here is the solution
1.Find ParentFragment in MainActivity by its TAG
2.And from the ParentFragemnt instance find ChildFragment with its TAG using getChildSupportManager()
3.And now create ChildAdapter variable global in ChildFragment and make it public
4.And from ChildFragment instance access the ChildAdapter
5.And than you can access MyMethod() from ChildAdapter variable
I usually use this method in the Activity which has to replace the Fragments:
/**
* This method is used to load the fragment once an item gets selected
*
* #param fragment This is the chosen fragment you want to select
*/
public void loadFragmentActivityFrameLayout(final Fragment fragment) {
// create a transaction for transition here
final FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
// put the fragment in place
transaction.replace(
R.id.frameLayoutId,
fragment,
fragment.getClass().getSimpleName());
// this is the part that will cause a fragment to be added to back stack,
// this way we can return to it at any time using this tag
if(fragment instanceof Fragment1){
transaction.addToBackStack(Fragmen1.class.getSimpleName());
}else if(fragment instanceof Fragment2){
transaction.addToBackStack(Fragment2.class.getSimpleName());
}else if(fragment instance of Fragment3){
transaction.addToBackStack(Fragment3.class.getSimpleName());
}else if(fragment instanceof Fragment4){
transaction.addToBackStack(Fragment4.class.getSimpleName());
}
transaction.commit();
}
And then you can retrieve an instance of each Fragment in that Activity, like this:
Fragment1 frag1 =
(Fragment1)getSupportFragmentManager()
.findFragmentByTag(Fragment1.class.getSimpleName());
Fragment2 frag2 =
(Fragment2)getSupportFragmentManager()
.findFragmentByTag(Fragment2.class.getSimpleName());
Fragment3 frag3 =
(Fragment3)getSupportFragmentManager()
.findFragmentByTag(Fragment3.class.getSimpleName());
Fragment4 frag4 =
(Fragment4)getSupportFragmentManager()
.findFragmentByTag(Fragment4.class.getSimpleName());
And then, since you got an adapter, make it public in its Fragment, let's say "frag1", don't forget to make "MyMethod()" also public into the adapter :
public CustomAdapter adapter;
And finally you can retrieve any adapter method from the Activity:
frag1.adapter.MyMethod();
Hope I've been clear.
I have done many programs, where I have implemented multiple Fragments inside a Single Activity, but not when using Single Activity to host multiple Fragments as Tabs and then on Tap show another Fragments...
Using MaterialViewPager library, in which I am calling different different Fragments to show views in their respective Tabs.
Like For the First Tab, I am using two Fragments, where
In First Fragment, I am using RecyclerView... to show list of Menus.
And in Second Fragment, I am using RecyclerView... to show list of Items under particular Menu.
So here my question is How to call Fragment from Fragment.
mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), mRecyclerView ,new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Value value = valueList.get(position);
List<Learning> learning = value.getLearning();
// using when putting "item" data into same recyclerview
// but on back press just exiting, not showing list of Menus again
/**
learningAdapter = new LearningAdapter(learning, R.layout.card_learning, getActivity());
mRecyclerView.setAdapter(learningAdapter);
**/
ItemFragment fragment = new ItemFragment();
replaceFragment(fragment);
}
Method replaceFragment
public void replaceFragment(Fragment someFragment) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// using Fragment not Activity, so where can I use frame_container in xml
transaction.replace(R.id.frame_container, someFragment);
transaction.addToBackStack(null);
transaction.commit();
}
you can have a callback interface that is implemented by the activity which hosts these two fragments. Fragment A will use the call back to notify the activity to replace A with fragment B. Depending on your need, you can pass parameters across through the callback method itself.
Your callback interface:
public interface YourCallback {
public void methodWhichReplacesFragmentAwithB(params...);
}
Your Activity hosting fragments:
public class YourActivity extends ... implements YourCallback {
..
..
#Override
public void methodWhichReplacesFragmentAwithB(params...) {
//insert replace fragment code here
}
}
Your fragment will have a callback object, YourCallback callbackObj;. This callback object can be initialised using the activity (pass as this from activity) itself since the activity has the implementation of the interface. Now, you can use
callbackObj.methodWhichReplacesFragmentAwithB(actual_params...);
to replace the fragment. This callback interface can be exploited for other communications to parent Activity as well as other fragment hosted in that activity.
To replace fragment,
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, someFragment).addToBackStack("null").commit();
You can try this:
YourFragment fragment = new YourFragment();
FragmentTransaction transaction = ((AppCompatActivity) mContext).getSupportFragmentManager()
.beginTransaction();
transaction.replace(R.id.frame, fragment);
transaction.addToBackStack(null);
transaction.commit();
There is One option which i have been using from long time before. I will added the solution with clear example.
So you want to pass the value from fragment A to fragment B
So, here what you want to do is, you have pass the value through the activity.
1) you pass the value from fragment A to activity
2) then activity to fragment B
Step 1: first create an Interface Like below in fragment A
public interface HomePage {
void onHomeButtonsClicked(String clickedButton);
}
public void setOnHomeButtonClicked(HomePage homePage) {
this.homePage = homePage;
}
Step 2: then create the instance like below in Activity. where fragment created in PagerAdapter
((FragmentA) fragment).setOnHomeButtonClicked(new FragmentA.HomePage() {
#Override
public void onHomeButtonsClicked(String buttonClicked) {
pageSelected.onHomeButtonsClicked(selectedPage);
}
}
});
Step 3: then create the interface in Activity like below.
public interface PageSelected {
void onHomeButtonsClicked(String clickedButton);
}
public void setOnHomeButtonClicked(PageSelected pageSelected) {
this.pageSelected = pageSelected;
}
step 3: then add the following method in fragment B in onCreateView or onResume()
((MainActivity) getActivity()).setOnHomeButtonClicked(new MainActivity.PageSelected() {
#Override
public void onHomeButtonsClicked(String clickedButton) {
//fragment B received the value here
}
});
Step 5: finally add the line in fragment A in button click or where you want to pass the value.
homePage.onHomeButtonsClicked("Some String , by this code it is in String. you can change in your own data type");
You can rise your question if you face any difficulties.
I have a ListView with several rows. Each row has a button.
I want the button to start a FragmentTransaction to replace the Fragment that the ListView is in.
However, in the getView() method of the Adapter, this line does not work:
FragmentTransaction t = getContext().getSupportFragmentManager().beginTransaction();
It does not like the context.
Can this be done in this way or does the Transaction have to happen elsewhere?
First get the context in your Constructor and then try following code,
FragmentTransaction ft = ((FragmentActivity)context).getSupportFragmentManager().beginTransaction();
getSupportFragmentManager() is only defined for the class FragmentActivity, not for Context. Thus, the compiler can't resolve the call if you try to call it on an object of type Context.
You can use reflection to do this in a safe way. This will always work as long as you pass your FragmentActivity as the Context. Note: FragmentActivity is a subclass of Context, and thus you can pass FragmentActivity wherever you can pass Context.
So use this code instead:
if (getContext() instanceof FragmentActivity) {
// We can get the fragment manager
FragmentActivity activity = (FragmentActivity(getContext()));
FragmentTransaction t = activity.getSupportFragmentManager().beginTransaction();
}
I'd suggest you to pass FragmentManager instance to the Adapter constructor like that:
public class YourAdapter extends...
private FragmentManage mFragmentManager;
public YourAdapter(FragmentManager fm) {
mFragmentManager = fm;
}
And use it explicitly:
FragmentTransaction ft = mFragmentManager.beginTransaction();
That should give you posibility to initialize Adapter with either Fragment.getFragmentManager() or FragmentActivity.getSupportFragmentManager() instance, since they are pointed at the same object
I have a linear layout (layout_container in skeleton.xml) which is inflated with a ListFragment (menufragment) when the activity is created. Then, when the user performs a click, this layout is replaced with another ListFragment (albumsfragment).
The problem is that when I press the back button, I go back indeed to the menufragment but the list is twice longer because it has been filled up again with the same items. How could I avoid this ?
OnCreate method, inside the Activity:
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.skeleton);
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
MenuFragment menufragment = new MenuFragment();
fragmentTransaction.add(R.id.layout_container, menufragment, "menufragment");
fragmentTransaction.commit();
}
OnClick method, inside the Activity:
public void OnMenuClick() {
AlbumsFragment albumsfragment = new AlbumsFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.layout_container, albumsfragment, "albumsfragment");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
My Fragment class code :
public class MenuFragment extends ListFragment{
ArrayList<MenuItem> m_parts = new ArrayList<MenuItem>();
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
MenuAdapter m_adapter;
m_parts.add(new MenuItem ("item1"));
m_parts.add(new MenuItem ("item2"));
m_parts.add(new MenuItem ("item3"));
m_parts.add(new MenuItem ("item4"));
m_adapter = new MenuAdapter(getActivity(), R.layout.menu_row, m_parts);
setListAdapter(m_adapter);
So each time I go back from AlbumFragment to MenuFragment, the list in MenuFragment grows as item1,item2,item3,item4 are added once again.
I've try to add the check if (savedInstanceState == null) before the transaction of the MenuFragment but doesn't change anything.
What should I do to make MenuFragment be popped up from the back Stack without being inflated again with these items ?
Thanks.
Take a look at the Fragment lifecycle. onActivityCreated() will be called everytime when returning to aFragment. Try, instead, to move your implementation to onCreate() and that should fix your duplication issue.
Probably you can also check for the size of the arraylist and then clear it onActivityCreated() before populating the arrayList.
if(m_parts != null && m_parts.size()>0){
//Clear the contents of the arrayList m_parts
m_parts.clear();
}
And then add the data to the arrayList.
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.