I'm trying to crate a viewpager transition inside a fragment class which itself derived from another fragment class. Whenever I'm trying to create the viewpager its showing the following error.
02-09 11:28:34.321: E/AndroidRuntime(8520): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.gm.gakkmusic/com.gm.gakkmusic.MainActivity}: java.lang.IllegalStateException: Recursive entry to executePendingTransactions
02-09 11:28:34.321: E/AndroidRuntime(8520): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2338)
02-09 11:28:34.321: E/AndroidRuntime(8520): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390)
After searching for a while in StackOverflow I found that I've to use getChildFragmentManager() while nesting a child fragment to its main fragment but I'm kinda confused about the whole process. It would be nice if anyone can figure this problem and give a quick solution.
Sources are given below,
This is where the Fragment1 is created from the MainActivity.class
#Override
public void onNavigationDrawerItemSelected(int position) {
FragmentManager fragmentManager = getSupportFragmentManager();
switch (position) {
case 0:
fragmentManager.beginTransaction()
.replace(R.id.container, new Fragment1())
.commit();
break;
}
}
Fragment1.class is the parent Fragment and inside it the child viewpager transition is created,
public class Fragment1 extends Fragment implements OnItemClickListener {
private Fragment contentFragment;
SliderFragment sliderFragment;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
if (savedInstanceState != null) {
if (fragmentManager.findFragmentByTag(SliderFragment.ARG_ITEM_ID) != null) {
sliderFragment = (SliderFragment) fragmentManager
.findFragmentByTag(SliderFragment.ARG_ITEM_ID);
contentFragment = sliderFragment;
}
} else {
sliderFragment = new SliderFragment();
switchContent(sliderFragment, SliderFragment.ARG_ITEM_ID);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View content = inflater.inflate(R.layout.fragment1_layout, container,
false);
return content;
}
#Override
public void onSaveInstanceState(Bundle outState) {
if (contentFragment instanceof SliderFragment) {
outState.putString("content", SliderFragment.ARG_ITEM_ID);
}
super.onSaveInstanceState(outState);
}
public void switchContent(Fragment fragment, String tag) {
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
while (fragmentManager.popBackStackImmediate())
;
if (fragment != null) {
FragmentTransaction transaction = fragmentManager
.beginTransaction();
transaction.replace(R.id.content_frame, fragment, tag);
if (!(fragment instanceof SliderFragment)) {
transaction.addToBackStack(tag);
}
transaction.commit();
contentFragment = fragment;
}
}
public void onBackPressed() {
FragmentManager fm = getActivity().getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
super.getActivity().onBackPressed();
} else if (contentFragment instanceof SliderFragment
|| fm.getBackStackEntryCount() == 0) {
getActivity().finish();
}
}
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Log.i(LOG_TAG, "onItemClick: " + position);
Log.d(LOG_TAG, "checked items: " + listView.getCheckedItemCount());
Log.d(LOG_TAG,
"checked positions: " + listView.getCheckedItemPositions());
}
}
UPDATE: I've already solved the problem by replacing all getSupportFragmentManager() to getChildFragmentManager() but I'm still looking for an efficient way to solve this.
Related
i have one activity which contains spinner control in appbar. in homeActivity i'm using fragment which have default fragment as parentoptionfragment, from that fragment there are 3 option to change the fragments, if i have choosen one fragment from parentoption fragment and i want to change spinner value then the fragment should be updated without adding to backstack means if i press back button then it should call parent optionfragment, but when i'm trying to do so i'm getting error.
public void GetChildData(String token) {
ParentOptionsFragment fragment =new ParentOptionsFragment();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
tv_childClassname.setText(classNameArr[position]);
tv_childSchoolName.setText(schoolNameArr[position]);
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
if (f instanceof ChildMapFragment){
Toast.makeText(HomeActivity.this, "refreshing childmapfragment", Toast.LENGTH_SHORT).show();
ChildMapFragment fragment = new ChildMapFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStackImmediate (fragment.getClass().getName(), 0);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}else if(f instanceof ParentOptionsFragment){
Toast.makeText(HomeActivity.this, "spinner changed from ParentOptionsFragment", Toast.LENGTH_SHORT).show();
}
}
parentoptionfragment.java
public class ParentOptionsFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_parent_options, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
final ImageView img1=(ImageView)view.findViewById(R.id.imageView);
ImageView img2=(ImageView)view.findViewById(R.id.imageView2);
ImageView img3=(ImageView)view.findViewById(R.id.img_transport);
img3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ChildMapFragment fragment = new ChildMapFragment();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
/*final ViewTreeObserver vto = img1.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
int x;
img1.getViewTreeObserver().removeOnPreDrawListener(this);
x = img1.getMeasuredWidth();
img1.setLayoutParams(new LinearLayout.LayoutParams(x,x));
return true;
}
});*/
}
}
childfragment.java
public class ChildFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_child_map, container, false);
}
}
homeActivity ---> defaultfragment-- parentoptionfragment
parentoptiofragment---> childfragment
using spinner update childfragment without backstack
onbackpress of childfragment --> parentoptionfragment
replace
Toast.makeText(HomeActivity.this, "refreshing childmapfragment", Toast.LENGTH_SHORT).show();
ChildMapFragment fragment = new ChildMapFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStackImmediate (fragment.getClass().getName(), 0);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
with :
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack()
update :
on your child fragment add a method : update() and call it :
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container)
if(fragment isInstanceOf ChildMapFragment ){
((ChildMapFragment )fragment).update() //call your update method here
}
FragmentManager fragmentManager = getSupportFragmentManager();
// String f_name=fragment.getClass().getName();
if (!fragmentManager.popBackStackImmediate(tag, 0)) {
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.content_frame, fragment, tag);
ft.addToBackStack(tag);
ft.commit();
}
to Refresh fragment implement back stack in activity like this
#Override
public void onBackStackChanged() {
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fr = fragmentManager.findFragmentById(R.id.content_frame);
if (fr != null) {
fr.onResume();
}
}
here pass different tag base on different fragment
I wanna inflate some fragment from an activity (which is not main but is activity).
I do exactly like this instruction:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
YourFragment fragment = new YourFragment();
fragmentTransaction.replace(android.R.id.content, fragment);//here is the error
fragmentTransaction.commit();
but in the one before last line, editor shows error saying:
2nd argument wrong type.Found:max.mzf.max.fragment.Required:android.app.fragment
this is my own code:
Activity
public class QuizCard extends FragmentActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.quiz_card);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
QcardFragment fragment = new QcardFragment();
fragmentTransaction.replace(R.id.your_placeholder, fragment );
fragmentTransaction.commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.card_menu, menu);
return true;
}
and this is QcardFragment:
public class QcardFragment extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//get data from Argument
}
public void onCardClick(View view) {
flipCard();
}
private void flipCard() {
View rootLayout = (View) getActivity().findViewById(R.id.main_activity_root);
View cardFace = (View) getActivity().findViewById(R.id.main_activity_card_face);
View cardBack = (View) getActivity().findViewById(R.id.main_activity_card_back);
FlipAnimation flipAnimation = new FlipAnimation(cardFace, cardBack);
if (cardFace.getVisibility() == View.GONE) {
flipAnimation.reverse();
}
rootLayout.startAnimation(flipAnimation);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.qcardfragment, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
What's wrong?
Make sure that your fragment class extends Fragment from android native library. If you are using external implementation try to change
FragmentManager fragmentManager = getFragmentManager();
to
FragmentManager fragmentManager = getSupportFragmentManager();
I'm trying to update the text of my TextView in my FragmentB through the Button in my FragmentA. But whenever I click the Button, nothing happens in my TextView. What could be the problem? Here's my code:
Communicator.java:
public interface Communicator {
public void respond(String data);
}
MainActivity.java:
public class MainActivity extends FragmentActivity implements Communicator{
ViewPager viewPager = null;
FragmentManager fragmentManager = getSupportFragmentManager();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.pager);
viewPager.setAdapter(new MyAdapter(fragmentManager));
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
FragmentB fragB = new FragmentB();
fragmentTransaction.add(R.id.pager, fragB, "frag_tag");
fragmentTransaction.commit();
}
public class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter (FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = null;
if (i == 0)
{
fragment = new FragmentA();
}
if (i == 1)
{
fragment = new FragmentB();
}
if (i == 2)
{
fragment = new FragmentC();
}
if (i == 3)
{
fragment = new FragmentD();
}
if (i == 4)
{
fragment = new FragmentE();
}
if (i == 5)
{
fragment = new FragmentF();
}
return fragment;
}
#Override
public int getCount() {
return 6;
}
}
#Override
public void respond(String data) {
// TODO Auto-generated method stub
FragmentB f2 = (FragmentB) fragmentManager.findFragmentByTag("frag_tag");
f2.changeText(data);
}
}
FragmentA:
public class FragmentA extends Fragment implements OnClickListener {
int counter = 0;
Button button1;
Communicator comm;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragmenta, container, false);
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
comm = (Communicator) getActivity();
button1 = (Button) getActivity().findViewById(R.id.button1);
button1.setOnClickListener(this);
}
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
counter++;
comm.respond("The button was clicked" + counter + "times");
}
}
FragmentB:
public class FragmentB extends Fragment {
TextView text1;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragmentb, container, false);
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
text1 = (TextView) getActivity().findViewById(R.id.textView1);
}
public void changeText(String data) {
// TODO Auto-generated method stub
text1.setText(data);
}
}
The host activity can deliver messages to a fragment by capturing the Fragment instance with findFragmentById(), then directly call the fragment's public methods.
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
} else {
// Otherwise, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
For more detail please follow this link http://developer.android.com/training/basics/fragments/communicating.html#Deliver
I have a NavigationDrawer which I use to switch between Fragments. What i would like to do is have a button in one of my fragments which acts as a 'shortcut' to another Fragment in the NavigationDrawer.
In the NavigationDrawer I switch fragments like this:
private class DrawerItemClickListener implements
ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
selectItem(position);
}
}
public void selectItem(int position) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
String fragmentTag = String.valueOf(position);
FragmentBase fragment = (FragmentBase) fragmentManager
.findFragmentByTag(fragmentTag);
if (null == fragment) {
fragment = createFragmentByPosition(position);
}
if (null == fragment)
return;
if (fragment.isAdded()) {
fragmentTransaction.show(fragment);
} else {
fragmentTransaction.replace(R.id.content_frame, fragment, fragmentTag);
}
if (mCurrentFragment != null) {
fragmentTransaction.hide(mCurrentFragment);
}
mCurrentFragment = fragment;
fragmentTransaction.commitAllowingStateLoss();
mDrawerList.setItemChecked(position, true);
setTitle(mNoterActivities[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
private FragmentBase createFragmentByPosition(int position) { // FragmentBase just extends Fragment
FragmentBase fragment = null;
if (position == 0) {
fragment = new Fragment1();
Bundle args = new Bundle();
fragment.setArguments(args);
} else if (position == 1) { // Reminder
fragment = new Fragment2();
Bundle args = new Bundle();
fragment.setArguments(args);
}
return fragment;
}
I'm not sure how I would go about doing this. I tried getting an instance of the NavigationDrawer class and then calling selectItem with the desired position, but this doesn't work as it gives an error "no view found".
In the NavigationDrawer class:
public Navigation_Drawer getInstance() {
if (null == instance) {
instance = new Navigation_Drawer();
}
return instance;
}
In FragmentB (position 1):
//onClick
Navigation_Drawer nd = new Navigation_Drawer().getInstance();
nd.selectItem(0); // Try to go to FragmentA
This seems far too simple so no wonder it doesn't work!
First, on selectItem method, using add method instead of replace method:
public void selectItem(int position) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
String fragmentTag = String.valueOf(position);
FragmentBase fragment = (FragmentBase) fragmentManager.findFragmentByTag(fragmentTag);
if (null == fragment) {
fragment = createFragmentByPosition(position);
}
if (null == fragment)
return;
if (fragment.isAdded()) {
fragmentTransaction.show(fragment);
} else {
// fragmentTransaction.replace(R.id.content_frame, fragment, fragmentTag);
fragmentTransaction.add(R.id.content_frame, fragment, fragmentTag);
}
if (mCurrentFragment != null) {
fragmentTransaction.hide(mCurrentFragment);
}
mCurrentFragment = fragment;
fragmentTransaction.commitAllowingStateLoss();
mDrawerList.setItemChecked(position, true);
setTitle(mNoterActivities[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
Second, getInstance method in Navigation_Drawer should not create a new Navigation_Drawer when instance is null, set instance to this in onCreate in Navigation_Drawer, then return instance when call getInstance:
private static Navigation_Drawer mInstance;
public static Navigation_Drawer getInstance() {
return mInstance;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
mInstance = this;
// other codes here:
}
The id to the QuickNoteFragment is 0, and to PendViewPager is 1. You can turn to PendViewPager in QuickNoteFragment:
Navigation_Drawer.getInstance().selectItem(1);
-
update1: how to pass data to fragment:
QuickNoteFragment and HistoryFragement have the same parent Class: FragmentBase, we add a method named onDataIn to receive data:
public class FragmentBase extends Fragment {
public void function onDataIn(Object data) {
}
}
We should change selectItem, add a paraments to receive data:
public void selectItem(int position, Object data) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
String fragmentTag = String.valueOf(position);
FragmentBase fragment = (FragmentBase) fragmentManager.findFragmentByTag(fragmentTag);
if (null == fragment) {
fragment = createFragmentByPosition(position);
}
if (null == fragment)
return;
// call onDataIn() method.
fragment.onDataIn(data);
if (fragment.isAdded()) {
fragmentTransaction.show(fragment);
} else {
// fragmentTransaction.replace(R.id.content_frame, fragment, fragmentTag);
fragmentTransaction.add(R.id.content_frame, fragment, fragmentTag);
}
if (mCurrentFragment != null) {
fragmentTransaction.hide(mCurrentFragment);
}
mCurrentFragment = fragment;
fragmentTransaction.commitAllowingStateLoss();
mDrawerList.setItemChecked(position, true);
setTitle(mNoterActivities[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
In order to make selectItem compatible, we should add a overloaded selectItem method.
public void selectItem(int postion) {
selectItem(position, null);
}
In this way, we do not need to change the old code where called selectItem and did not need pass a data to fragement.
I am new to Fragments. I tried simple fragment example. But it throws the error. I don't know what is wrong.
public class NewActivity extends Activity {
int mStackLevel = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
Fragment newFragment = NewFragment
.newInstance(mStackLevel);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.simple_fragment, newFragment).commit();
} else {
mStackLevel = savedInstanceState.getInt("level");
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("level", mStackLevel);
}
public static class NewFragment extends Fragment {
int mNum;
Context context;
static NewFragment newInstance(int num) {
NewFragment f = new NewFragment();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNum = getArguments() != null ? getArguments().getInt("num") : 1;
context = getActivity();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.example_fragment, container,
false);
return v;
}
}
}
My logcat shows:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.FragmentExample/com.example.FragmentExample.NewActivity}: java.lang.IllegalArgumentException: No view found for id 0x7f07003c for fragment NewFragment{40ff0850 #0 id=0x7f07003c}
ft.add(R.id.simple_fragment, newFragment).commit();
you missed setContentView for your Activity. Your Fragment can not be added without a View hierarchy.
Note : Your Fragment is hosted by an activity. So you need to set the content to the activity first.
Just replace this method with your method
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(Your_layout_file);
if (savedInstanceState == null) {
Fragment newFragment = NewFragment
.newInstance(mStackLevel);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.simple_fragment, newFragment).commit();
} else {
mStackLevel = savedInstanceState.getInt("level");
}
}
you missed this line setContentView(Your_layout_file);
This answer highlights a silly mistake that may occur, that arises when nesting fragments or you are converting activities to fragments.
If you are trying to replace a fragment within a fragment with the fragmentManager but you are not inflating the parent fragment that can cause an issue.
In BaseFragment.java OnCreateView:
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.replace(R.id.container, new DifferentFragment())
.commit();
}
return super.onCreateView(inflater, container, savedInstanceState);
Replace super.onCreateView(inflater, container, savedInstanceState);
with inflating the correct layout for the fragment:
return inflater.inflate(R.layout.base_fragment, container, false);