why is getSupportFragmentManager().findFragmentById returning null - android

From OverlayActivity:
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG,"onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_overlay);
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first chatRootFragment
if (findViewById(R.id.video_player_fragment_container) != null) {
if (savedInstanceState != null) {
return;
}
FullScreenVideoPlayerUnderlayFragment mMessageListFragment = new FullScreenVideoPlayerUnderlayFragment();
if (mMessageListFragment != null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.video_player_fragment_container, mMessageListFragment);
transaction.commit();
} else {
Log.e("OverlayActivity", "Error in creating chatRootFragment");
}
}
// Instantiate a ViewPager and a PagerAdapter.
mPager = findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setCurrentItem(1);
}
#Override
public void onBackPressed() {
FullScreenVideoPlayerUnderlayFragment fragment = (FullScreenVideoPlayerUnderlayFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_full_screen_video_player_underlay_id);//<= NULL
OverlayActivity.super.onBackPressed();
}
The frgment:
public class FullScreenVideoPlayerUnderlayFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_full_screen_video_player_underlay, container, false);
}
#Override
public void onDestroy() {
getActivity().setResult(getActivity().RESULT_OK, getActivity().getIntent().putExtra("USER_DATA_EXTRA", "Yo User"));
super.onDestroy();
playlistManager.invokeStop();
exitFullscreen();
}
}
fragment_full_screen_video_player_underlay.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/fragment_full_screen_video_player_underlay_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black">
<com.devbrackets.android.exomedia.ui.widget.VideoView
android:id="#+id/video_play_activity_video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:useDefaultControls="true"/>
</RelativeLayout>
activity_overlay.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/video_player_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>

fragment_full_screen_video_player_underlay_id
is the id of your RelativeLayout.
From the documentation:
findFragmentById
Finds a fragment that was identified by the given id either when inflated from XML or as the container ID when added in a transaction. This first searches through fragments that are currently added to the manager's activity; if no such fragment is found, then all fragments currently on the back stack associated with this ID are searched.
This means that either your fragment is inflated from XML - in which case you will have to use the id of your <Fragment> element if any - or to the container with the given ID that hosts the fragment.
If you added your fragment using a transaction and you need to retrieve it later then use findFragmentByTag (String tag) and add the fragment using add
add (int containerViewId, Fragment fragment, String tag)

I should use
FullScreenVideoPlayerUnderlayFragment fragment = (FullScreenVideoPlayerUnderlayFragment) getSupportFragmentManager().findFragmentById(R.id. video_player_fragment_container);
instead of
FullScreenVideoPlayerUnderlayFragment fragment = (FullScreenVideoPlayerUnderlayFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_full_screen_video_player_underlay_id);//<= NULL

Instead of finding fragment what I should do is I would add a frame layout in activity_main.xml and i made a function to load a fragment in that frame layout here's a function.
public void loadFragment(Fragment fragment, String title) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.frameLayoutId, fragment, title);
transaction.commit();
}
This worked for me very good I hope same for you...
happy coding. :)

Related

Shared Element Transition Not Working Between Parent and Child Fragments (Nested Fragments)

In the Main Activity, I have BottomNavigationView where there are 3 different parent fragments. The parent fragment has recyclerview and on item click of recyclerview, I am launching child fragment for more details about the item. I am trying to implement Shared Element Transition between my two fragments (parent & child) but it's not happening.
There is no issue with launching child fragment also I have checked the transition name and it's the same in child fragment which I assign to an item in the adapter. I am using Random class to assign transition name to item as in single parent fragment I have many recyclerviews. Here is my code:
Adapter
final String transition;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
transition = "transition" + new Random().nextInt(9999999);
viewHolder.image.setTransitionName(transition);
}
viewHolder.container.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mCallback.itemClicked(i, book, viewHolder.image, transition);
}
});
Parent Fragment
#Override
public void itemClicked(int pos, Book book, View view, String transition) {
MainActivity activity = (MainActivity) getActivity();
ChildFragment myFragment = new ChildFragment();
Bundle bundle = new Bundle();
bundle.putString(IntentExtraKeys.TRANSITION_NAME, transition);
myFragment.setArguments(bundle);
activity.showFragmentWithTransition(this, myFragment, ChildFragment.class.getName(), view, transition);
}
Activity
public void showFragmentWithTransition(Fragment current, Fragment newFragment, String tag, View sharedView, String sharedElementName) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
current.setSharedElementReturnTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
current.setExitTransition(TransitionInflater.from(this).inflateTransition(android.R.transition.no_transition));
newFragment.setSharedElementEnterTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
newFragment.setEnterTransition(TransitionInflater.from(this).inflateTransition(android.R.transition.no_transition));
}
FragmentManager manager = current.getChildFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.child_fragment, newFragment, tag);
transaction.addToBackStack(tag);
transaction.addSharedElement(sharedView, sharedElementName);
transaction.commit();
}
default_transition
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeTransform />
<changeBounds />
</transitionSet>
Child Fragment
Bundle b = getArguments();
if (b != null) {
String transitionName = b.getString(IntentExtraKeys.TRANSITION_NAME);
Logger.info("opening bundle book fragment:" + transitionName);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
image.setTransitionName(transitionName);
}
}
Here is the sample project of issue:
https://gitlab.com/iskfaisal/transition-issue
I am trying to implement Shared Element Transition between my two fragments (parent & child) but it's not happening.
Nothing is happening or at least it looks like nothing is happening because you're using only <changeTransform/> and <changeBounds /> in your default_transition.xml. If bounds of both Fragments coincide, there's nothing to "transit".
However, if you add additional animation elements to the file then the transition is actually visible (even if bounds coincide).
Introduction
I have created a sample project similar to yours - BottomNavigationView with a NavHostFragment containing 2 parent Fragments - DashboardFragment and HomeFragment.
Initially, DashboardFragment loads DashboardListFragment that consists of a simple RecyclerView. If any RecyclerView item is clicked then DashboardFragment loads DashboardDetailFragment (bounds in DashboardDetailFragment and DashboardListFragment coincide).
Transition Behaviour
Then, I pretty much reused your showFragmentWithTransition(...) and tried to click each element in the list to check if any transition would be visible - it wasn't.
Hence, I modified the file by adding a simple <slide/> element as below:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet>
<slide/>
<changeTransform />
<changeBounds />
</transitionSet>
And the sliding transition was right there.
I also tried other elements like <fade/> or <explode/> or others - all of them worked just fine too.
Conclusion
Even if a transition is not visible, it doesn't mean it's not happening. You should try other animation elements to see it work.
UPDATE
Since you provided a link to your github code, I peeked into it and brought it to the working condition. I'll leave it up to you to improve it further.
So, basically, your HomeFragment layout file contained both RecyclerView and a placeholder for your child Fragment at the same time. Instead, I split your HomeFragment into 2 entities - one for your parent Fragment HomeFragment containing only the placeholder for any child Fragment and HomeFragmentList containing your previous parent logic.
Then, when a picture is selected, HomeFragment replaces your HomeFragmentList with a ChildFragment. And...it works!
This way, you don't need to use your Activity for creating a child Fragment and it's more independent.
Below, I provide the relevant code that had to be modified.
Code
HomeFragment (new parent)
public class HomeFragment extends Fragment {
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
HomeFragmentList homeFragmentList = new HomeFragmentList();
FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.child_fragment, homeFragmentList, homeFragmentList.getClass().getName());
fragmentTransaction.commit();
}
}
HomeFragmentList (old parent)
public class HomeFragmentList extends Fragment implements AdapterListener {
RecyclerView recyclerView;
private ArrayList<String> images = new ArrayList<>();
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_home_list, container, false);
recyclerView = root.findViewById(R.id.recycler_view);
getImages();
LinearLayoutManager manager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
recyclerView = root.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(manager);
AdapterClass adapter = new AdapterClass(this, images);
recyclerView.setAdapter(adapter);
return root;
}
void getImages() {
images.add("https://rukminim1.flixcart.com/image/832/832/book/0/1/9/rich-dad-poor-dad-original-imadat2a4f5vwgzn.jpeg?q=70");
images.add("https://www.seeken.in/wp-content/uploads/2017/06/The-4-Hour-Work-Week.jpeg");
images.add("https://www.seeken.in/wp-content/uploads/2017/06/Managing-Oneself.jpeg");
images.add("https://www.seeken.in/wp-content/uploads/2017/07/How-to-Win-Friends-and-Influence-People.jpeg");
images.add("https://www.seeken.in/wp-content/uploads/2017/07/THINK-LIKE-DA-VINCI-7-Easy-Steps-to-Boosting-your-Everyday-Genius.jpeg");
images.add("https://www.seeken.in/wp-content/uploads/2017/07/How-To-Stop-Worrying-And-Start-Living.jpg");
images.add("https://www.seeken.in/wp-content/uploads/2017/08/THE-INTELLIGENT-INVESTOR.jpeg");
images.add("https://www.seeken.in/wp-content/uploads/2017/08/Awaken-the-Giant-within-How-to-Take-Immediate-Control-of-Your-Mental-Emotional-Physical-and-Financial-Life.jpg");
images.add("https://www.seeken.in/wp-content/uploads/2017/08/E-MYTH-REVISITED.jpeg");
images.add("https://images-na.ssl-images-amazon.com/images/I/41axGE4CehL._SX353_BO1,204,203,200_.jpg");
images.add("https://rukminim1.flixcart.com/image/832/832/book/0/1/9/rich-dad-poor-dad-original-imadat2a4f5vwgzn.jpeg?q=70");
}
#Override
public void itemClicked(int pos, ModelClass object, View view, String transition) {
MainActivity activity = (MainActivity) getActivity();
ChildFragment myFragment = new ChildFragment();
Bundle bundle = new Bundle();
bundle.putString("IMAGE_URL", object.getItem(pos));
bundle.putInt("POSITION", pos);
bundle.putString("TRANSITION_NAME", transition);
myFragment.setArguments(bundle);
Log.i("HOME FRAGMENT-DEBUG", transition + "/" + view.getTransitionName());
showFragmentWithTransition(getParentFragment(), myFragment, ChildFragment.class.getName(), view, transition);
}
public void showFragmentWithTransition(Fragment current, Fragment _new, String tag, View sharedView, String sharedElementName) {
FragmentManager manager = current.getChildFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
if (sharedView != null && sharedElementName != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
current.setSharedElementReturnTransition(TransitionInflater.from(getContext()).inflateTransition(R.transition.default_transition));
current.setExitTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.no_transition));
_new.setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(R.transition.default_transition));
_new.setEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.no_transition));
transaction.addSharedElement(sharedView, sharedElementName);
Log.i("ACTIVITY-DEBUG", sharedElementName + "/" + sharedView.getTransitionName());
}
}
transaction.replace(R.id.child_fragment, _new, tag);
transaction.addToBackStack(tag);
transaction.commit();
}
}
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/child_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
fragment_home_list.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFF">
<androidx.core.widget.NestedScrollView
android:id="#+id/home_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginLeft="9dp"
android:layout_marginRight="9dp">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:orientation="vertical">
</androidx.recyclerview.widget.RecyclerView>
</RelativeLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFF">
<androidx.appcompat.widget.Toolbar
android:id="#+id/z_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="4dp">
<RelativeLayout
android:id="#+id/header_container"
android:layout_width="match_parent"
android:layout_height="56dp">
<ImageView
android:id="#+id/logo"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginRight="10dp"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:src="#mipmap/ic_launcher_round"
android:contentDescription="#string/app_name" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/logo"
android:textColor="#000"
android:textSize="16sp"
android:text="Home" />
</RelativeLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</RelativeLayout>
Remark
Please note that the transition for <changeTransform/> and <changeBounds /> is visible because bounds of a selected View in HomeFragmentList are different from that in the child Fragment.
Shared element transition does not work properly with FragmentTransaction.add method because parent fragment is still alive and resumed. Try
transaction.replace(R.id.child_fragment, newFragment, tag);
Check this discussion thread for more information.
I'm not sure about the rest of your setup, but for Shared Element Transitions to work correctly, you need to add setReorderingAllowed(true) to your Fragment Transaction like this:
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.child_fragment, newFragment, tag);
transaction.addToBackStack(tag);
transaction.addSharedElement(sharedView, sharedElementName);
transaction.setReorderingAllowed(true); // Add this
transaction.commit();

Replacing fragments dynamically?

Now I know this is a very simple question and was asked many times, but non of the solutions provided previously has worked for me.
I have an activity with a FrameLayout as follows:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/replace_me"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</FrameLayout>
</android.support.constraint.ConstraintLayout>
And in my MainActivity class I have the following:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
replaceFragment(new ChooseLevelFragment(), false);
}
}
public void replaceFragment(Fragment fragment, boolean addToBackStack) {
FragmentTransaction replace = getSupportFragmentManager().beginTransaction().replace(R.id.replace_me, fragment);
if (addToBackStack) {
replace.addToBackStack(null);
}
replace.commit();
Log.d(TAG, "Fragment replaced!");
}
The first fragment is being shown correctly. However, when the user clicks on an item from the menu and logs in, the app should replace the current fragment with the new one
private void showAuthenticationDialog() {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
Fragment fragmentByTag = getSupportFragmentManager().findFragmentByTag(AuthenticationDialogFragment.TAG);
if (fragmentByTag != null) {
fragmentTransaction.remove(fragmentByTag);
}
fragmentTransaction.addToBackStack(null);
AuthenticationDialogFragment authenticationDialogFragment = AuthenticationDialogFragment.newInstance(() -> {
replaceFragment(new ParentControlPanelFragment(), true);
});
authenticationDialogFragment.show(fragmentTransaction, AuthenticationDialogFragment.TAG);
}
The new fragment is not being replaced even after the commit. I can see my log message but not the new fragment. I'm not quite sure where the problem is.
The problem was that I was trying to replace the fragment before I dismiss the dialog.
The correct approach is to dismiss the dialog first then try to replace the fragment.

java.lang.IllegalArgumentException: No view found for id 0x1020002 (android:id/content) for fragment

I am trying to move from one fragment to another.. It shows following error during fragment transaction-
java.lang.IllegalArgumentException: No view found for id 0x1020002 (android:id/content) for fragment PhotosFragment2{41a57218 #3 id=0x1020002}
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:930)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1115)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1478)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:446)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:153)
at android.app.ActivityThread.main(ActivityThread.java:5086)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:821)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:584)
at dalvik.system.NativeStart.main(Native Method)
Below are the classes.I have used following code for fragment transaction
Fragment fragment = new PhotosFragment2();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(android.R.id.content, fragment);
fragmentTransaction.commit();
PhotosFragment.java
public class PhotosFragment extends Fragment {
private FragmentActivity myContext;
#Override
public void onAttach(Activity activity) {
myContext = (FragmentActivity) activity;
super.onAttach(activity);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.photos, container, false);
rootView.setVerticalScrollBarEnabled(false);
int[] mThumbIds = {
R.drawable.album8, R.drawable.album3,
R.drawable.album4, R.drawable.album8,
R.drawable.album6, R.drawable.album7,
R.drawable.album12, R.drawable.album10,
};
int[] mThumbIds2 = {
R.drawable.album8, R.drawable.album3,
R.drawable.album4,
R.drawable.album6, R.drawable.album7,
R.drawable.album9, R.drawable.album10,
R.drawable.album11, R.drawable.album12, R.drawable.album8,
R.drawable.album8, R.drawable.album3,
R.drawable.album4,
R.drawable.album6, R.drawable.album7,
R.drawable.album9, R.drawable.album10,
R.drawable.album11, R.drawable.album12, R.drawable.album8,
};
CustomGridSingle2 adapter = new CustomGridSingle2(myContext, mThumbIds);
GridView grid = (GridView)rootView.findViewById(R.id.gridView);
final ImageView img= (ImageView)rootView.findViewById(R.id.imageView7);
grid.setFocusable(false);
grid.setAdapter(adapter);
grid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fragment fragment = new PhotosFragment2();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(android.R.id.content, fragment);
fragmentTransaction.commit();
}
});
CustomGridSingle2 adapter2 = new CustomGridSingle2(myContext, mThumbIds2);
GridView grid2 = (GridView)rootView.findViewById(R.id.gridView2);
grid2.setFocusable(false);
grid2.setAdapter(adapter2);
grid2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fragment fragment = new PhotosFragment2();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(android.R.id.content, fragment);
fragmentTransaction.commit();
}
});
return rootView;
}
}
PhotosFragment2.java
public class PhotosFragment2 extends Fragment {
private FragmentActivity myContext;
#Override
public void onAttach(Activity activity) {
myContext = (FragmentActivity) activity;
super.onAttach(activity);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View rootView = inflater.inflate(R.layout.photos2, container, false);
myContext.getActionBar().hide();
return rootView;
}
}
Activity xml file
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:id="#+id/left_drawer_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#drawable/bgmenu"
android:orientation="vertical">
<RelativeLayout
android:id="#+id/profilelayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:paddingTop="10dp">
<ImageView
android:id="#+id/drawer_profile_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/drawer_profile_background"
android:layout_alignLeft="#+id/drawer_profile_background"
android:layout_alignRight="#+id/drawer_profile_background"
android:layout_alignTop="#+id/drawer_profile_background"
android:layout_marginBottom="7.667dp"
android:layout_marginLeft="6.5dp"
android:layout_marginRight="8.3dp"
android:layout_marginTop="7.667dp"
android:scaleType="centerCrop"></ImageView>
<ImageView
android:id="#+id/drawer_profile_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:scaleType="centerCrop"
android:src="#drawable/profileblock">
</ImageView>
<ImageView
android:id="#+id/settingicon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/drawer_profile_background"
android:layout_marginLeft="-15dp"
android:layout_toRightOf="#+id/drawer_profile_background"
android:background="#drawable/settings" />
<textview
android:id="#+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/drawer_profile_background"
android:layout_centerHorizontal="true"
android:layout_marginTop="5dp"
android:text="Name"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:textColor="#android:color/white" />
</RelativeLayout>
<ListView
android:id="#+id/list_slidermenu"
style="#style/buttonStyle"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="30dp"
android:layout_weight="2"
android:cacheColorHint="#android:color/transparent"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="1dp"
android:listSelector="#android:color/transparent"
android:scrollbars="none" />
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
When you use fragmentTransaction.replace(R.id.container,fragment) it will remove any fragments that are already in the container and add your new one to the same container.
Now i can suggest you 2 things.First, if you want to use fragmentTransaction.replace(android.R.id.content, fragment); which you are doing right now,then don't set content for your Activity using setContentView.This should work fine then.To know what exactly android.R.id.content is you can refer this stackoverflow question and answer
Or Secondly, In the layout of your Activity have a FrameLayout whose id is content. And then use
fragmentTransaction.replace(R.id.content, fragment);
fragmentTransaction.addToBackStack(null);//add the transaction to the back stack so the user can navigate back
// Commit the transaction
fragmentTransaction.commit();
Hope this helps.
More Info:
From your comments it seems that you are having some problem in getting the idea of using FrameLayout in your Activity's layout(Not of any of the Fragment's layout).From the Documents
FrameLayout is designed to block out an area on the screen to display a single item. Generally, FrameLayout should be used to hold a single child view, because it can be difficult to organize child views in a way that's scalable to different screen sizes without the children overlapping each other.
So the main purpose of FrameLayout is to block the area required to fit the largest child view. If you use a FrameLayout as Fragment Container you can ensure that you always have the space available to accommodate the largest Fragment's layout.
So you can have your FrameLayout something like this in your Activity's layout xml file
<FrameLayout
android:id="#+id/content"
android:layout_height="match_parent"
android:layout_width="match_parent">
<!--you can put your existing views of your current xml here, so yes your entire xml is now inside this FrameLayout -->
</FrameLayout>
I don't use getSupportFragmentManager().
I use getChildFragmentManager() and it worked for me.
You can try it.
If you are trying to put Fragment into Fragment, use getChildFragmentManager()
If you are using ViewPager, use getChildFragmentManager() for pager adapter
viewPager.setAdapter(new ItemsAdapter(getChildFragmentManager()));
You have to set a content view in your Activity that your PhotosFragment is attached.
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
//...
}
i know this is very late. But it may work for other's.
I declared the id for each layout, like (3rd line bellow)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
Since Android 4.2 (API 17) nested fragments become avaliable.
See this
To place fragment inside other fragment use getChildFragmentManager()
Also available in support library.
I had the same error and after trying a lot of things I found that the problem was with the "id" and "getActivity().getSupportFragmentManager()".
Before i implement i like these
txt_more.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getChildFragmentManager()
.beginTransaction()
.replace(R.id.content_frame, new OpportunitiesFragment())
.commit(); }
});
Then i changed to these
txt_more.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
## Heading ##
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(android.R.id.content, new OpportunitiesFragment())
.commit(); }
});
Put this block of code in PhotosFragment2 onCreateView method:
View rootView = inflater.inflate(R.layout.photos2, null);
instead of:
View rootView = inflater.inflate(R.layout.photos2, container, false);
in my case I had to change
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.sample,
container);
to
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.sample,
container, false);
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);
The problem may be that you add a fragment and beginTransaction in some fragment like
getFragmentManager().beginTransaction().replace(android.R.id.content, ImageBrowseFragment.newInstance(bundle),"ImageBrowseFragment")
.addToBackStack(null).commit();
I just change getFragmentManager() to getActivity().getSupportFragmentManager()
Then everything goes fine
When you add a fragment in a fragment use android.R.id.content Or Window.ID_ANDROID_CONTENT,I guess it represents the root container of your fragment not the activity. So change to getActivity().getSupportFragmentManager() works it out
If you use ViewPager with fragments (pages) and try to show a new fragment from a page, you will get this error. I think, you cannot reference to a container of an Activity from a ViewPager's page.
In this case you should call getActivity(). Then in Activity write a method that will open a new fragment.
class YourActivity : AppCompatActivity() {
fun showNewFragment(title: String) {
val fm = supportFragmentManager
fm?.beginTransaction()?.apply {
val fragment = NewFragment.newInstance(title)
replace(R.id.container, fragment, NewFragment.TAG)
addToBackStack(null)
}?.commit()
}
}
class PageFragment : Fragment() {
private fun show() {
(activity as YourActivity).showNewFragment("New fragment")
}
}
If you call getParentFragment() and add a new fragment, then you will place a new fragment inside ViewPager:
class ViewPagerFragment : Fragment() {
fun showNewFragment(title: String) {
val fm = childFragmentManager
fm?.beginTransaction()?.apply {
val fragment = NewFragment.newInstance(title)
replace(R.id.container, fragment, NewFragment.TAG)
addToBackStack(null)
}?.commit()
}
}
class PageFragment : Fragment() {
private fun show() {
(parentFragment as? ViewPagerFragment)?.showNewFragment("New fragment")
}
}
Make sure the fragment id you are calling is in the class listed in setcontent in onCreate method. For my case, I was editing the layout from linear to constraint. So as not to mess with the working code, I made another layout but messed an id in the process so that what was on oncreate was the edited layout but the fragment being called was from the old layout. Apparently, in the new layout I gave it a different id name. Search the id of your fragment using ctrl+shift+f and see if the search results point to the layout you specified in the oncreate method. Goodluck.
The most common mistake that can be happened is, If you have more than one version of XML layout (let say v21 and v23) and you added <fragment> tag in lower version of XML only (or vice-versa).
So, please check you added <fragment> tag (or pageGroup, etc) in both of the versions.
You are trying to open fragment which fragmentContainer(the view in which you are trying to open fragment) is one or more level above from your current fragmentContainer.
Try to change your fragment hierarchy architecture.

Android Fragment Duplicate Objects in Layout

I'm trying to build an Android 4.0 App with the new fragments and action bar.
I'm doing well but I have a little problem now.
When I put a fragment inside a tab, and for example, a time picker in the fragment layout, in the emulator it will appear twice, one on top of the other.
Here is my code:
public class NetworksActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.networks);
// setup Action Bar for tabs
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// instantiate fragment for the tab
Fragment networksFragment = new NetworksFragment();
// add a new tab and set its title text and tab listener
actionBar.addTab(actionBar.newTab().setText("Sensors")
.setTabListener(new ActionTabListener(networksFragment)));
}}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<fragment
android:id="#+id/net_frag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name="my.package.test.NetworksFragment" />
</FrameLayout>
public class NetworksFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.networks_fragment, container, false);
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TimePicker
android:id="#+id/timePicker1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
public class ActionTabListener implements ActionBar.TabListener {
private NetworksFragment frag;
// Called to create an instance of the listener when adding a new tab
public ActionTabListener(NetworksFragment fragment) {
frag = fragment;
}
#Override
public void onTabReselected(Tab arg0, FragmentTransaction arg1) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.add(R.id.net_frag, frag, null);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(frag);
}
}
It seems like its putting two fragments (two copies) in the same activity.
Do you know what are causing this?
Thanks in advance.
It looks like you are defining a fragment in XML, which will instantiate it when that layout is inflated (from NetworksActivity.setContentView(R.layout.networks)) then you are creating another instance of it just below that.
Unless I am missing something, that is your problem. No need to define it in XML if you are going to instantiate it manually and add it yourself in code.
I had a similar problem. The way i solved it was to remove this code from my Fragment-class:
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
CameraFragment cameraFragment = new CameraFragment();
fragmentTransaction.add(R.id.spinnerFragment, spinnerFragment);
fragmentTransaction.commit();
And left this code from my fragment-XML:
<fragment
android:id="#+id/spinnerFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
class="com.example.SpinnerFragment" />
I guess you can do it the oposite way also :)

Dynamically add fragment into fragment

I haven't been able to find a way how to dynamically add fragment into existing dynamically added fragment. Do you know, if it is possible?
I am generating fragments this way:
FragmentManager fragMgr = getSupportFragmentManager();
FragmentTransaction xact = fragMgr.beginTransaction();
if(null == fragMgr.findFragmentByTag(FRAG1_TAG)) {
xact.add(10101010, new DateTime(), FRAG1_TAG);
}
if(null == fragMgr.findFragmentByTag(FRAG4_TAG)) {
xact.add(7777, new loginForm(), FRAG4_TAG);
}
xact.commit();
How to add into FRAG4_TAG fragment another one?
Edit2:
I hard coded it's id to be able to work with it in future (where ll is my linearLayout in XML):
FrameLayout frml4 = (FrameLayout)inflater.inflate(R.layout.frame,null);
frml4.setId(7777);
frml4.setBackgroundColor(Color.YELLOW);
ll.addView(frml4);
I assume the problem that you are running into is that there is not an inflated view to add the fragment to because the original fragment, FRAG4_TAG, has not been inflated before you are trying to add it.
You can pass enough information to FRAG4_TAG in the Arguments to let it know that it should create and add a fragment (or what all fragments you need it to have) to itself during it's onCreateView, after the view has been inflated...
The layout for the activity...
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="MyActivity"/>
<LinearLayout
android:orientation="vertical"
android:id="#+id/main_frag_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
The Activity...
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Fragment fragOne = new MyFragment();
Bundle arguments = new Bundle();
arguments.putBoolean("shouldYouCreateAChildFragment", true);
fragOne.setArguments(arguments);
ft.add(R.id.main_frag_container, fragOne);
ft.commit();
}
}
The layout for the fragment...
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="20dp">
<TextView
android:id="#+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Some fragment"/>
<LinearLayout
android:orientation="vertical"
android:id="#+id/frag_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
The fragment...
public class MyFragment extends Fragment {
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
ViewGroup layout = (ViewGroup) inflater.inflate(R.layout.frag_layout, container, false);
boolean shouldCreateChild = getArguments().getBoolean("shouldYouCreateAChildFragment");
if (shouldCreateChild) {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fm.beginTransaction();
Fragment fragTwo = new MyFragment();
Bundle arguments = new Bundle();
arguments.putBoolean("shouldYouCreateAChildFragment", false);
fragTwo.setArguments(arguments);
ft.add(R.id.frag_container, fragTwo);
ft.commit();
}
return layout;
}
}
This example covers the case where you need to dynamically add fragments to a fragment that HAS NOT already been inflated and added to the hierarchy. Adding a fragment to a fragment that HAS already been inflated and added to the hierarchy is as simple as just specifying the target fragments container that you want to add to by ID like you would normally.
As the documentation states "A fragment must always be embedded in an activity".
So when you add a "sub-fragment" it will always belong to the activity even if you add it within your fragment class. For example if you later decide to remove the containing fragment the sub fragments won't be automatically removed.
When I had to do the same I had to store in a vector the sub fragments and manually remove them in the onDestroy methods of my container fragment.
I think that fragments are not thought to be used like this
You cannot insert Fragments into other Fragments. (At least, not yet)
You can however replace Fragments with other Fragments with FragmentTransaction.replace(containerViewId, Fragment).
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.linear1, new activity()).commit();
}

Categories

Resources