I'am new in Android and I work with fragments. I have activity (MainActivity) and 3 Fragments, A->B->C. I need to back navigate from C fragment to B, from B to A and backward. I was cliked on Fragment A see A, clicked on B see B, clicked on C see C, but when I clicked Back my app was closed. Why ?
Here is a example what I call fragments
Fragment Subcategory = new Subcategory();
Bundle bundle = new Bundle();
bundle.putInt("id", i);
String title = dba.getTitle(i,true);
bundle.putString("title", title);
Subcategory.setArguments(bundle);
FragmentTransaction transaction_cat = getFragmentManager().beginTransaction();
transaction_cat.replace(R.id.fragment_container, Subcategory);
transaction_cat.addToBackStack(null);
transaction_cat.commit();
I can't found any simple example which show me how to navigate between fragments, and after reading this article I don't understand how it works.
Tell me please, and write example how I must do this.
I think you can try override method onBackPressed() for the activity.
update:
Here is part of my code.
public class MainActivity extends Activity {
RelativeLayout mContainer;
int count = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContainer = (RelativeLayout) findViewById(R.id.fragment_container);
addFragment();
}
private void addFragment() {
FragmentManager fm = getFragmentManager();
Fragment f = fm.findFragmentById(R.id.fragment_container);
if (f == null) {
f = new MainActivityFragment();
f.setArguments(getIntent().getExtras());
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_container, f);
ft.addToBackStack("" + count++);
ft.commit();
}
}
private void replaceFrament() {
FragmentManager fm = getFragmentManager();
Fragment f;
f = new BlankFragment();
f.setArguments(getIntent().getExtras());
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_container, f);
ft.addToBackStack("" + count++);
ft.commit();
}
public void onAddFragmentClick(View v) {
replaceFrament();
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivityFragment">
<RelativeLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"></RelativeLayout>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add Fragment"
android:layout_alignParentBottom="true"
android:onClick="onAddFragmentClick"/>
</RelativeLayout>
Related
I went through some questions and made the changes as I thought were necessary, but the application still crashes every time I press the button to replace fragments. The fragments have the usual code and are just for simple layouts. On the launch, the activity will display the fragment I first add.
Here's my MainActivity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final FragmentLogin fl = new FragmentLogin();
final FragmentRegistration fr = new FragmentRegistration();
final android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
final android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragcon, fr);
fragmentTransaction.commit();
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(fl.isVisible())
{
fl.onActivityCreated(savedInstanceState);
fragmentTransaction.replace(R.id.fragcon, fr);
fragmentTransaction.commit();
}
else {
fl.onActivityCreated(savedInstanceState);
fragmentTransaction.replace(R.id.fragcon, fl);
fragmentTransaction.commit();
}
}
});
}
}
And here's my activitymain.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.aditya.registrationnlogin.MainActivity">
<RelativeLayout
android:id="#+id/fragcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1.8"
android:layout_gravity="center_horizontal">
</RelativeLayout>
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="SWITCH" />
</LinearLayout>
You have to call fragmentManager.beginTransaction(); for every new transaction otherwise it will throw an exception
if(fl.isVisible())
{
//fl.onActivityCreated(savedInstanceState);
fragmentManager.beginTransaction().replace(R.id.fragcon, fr);
fragmentTransaction.commit();
}else{
//fl.onActivityCreated(savedInstanceState);
fragmentManager.beginTransaction().replace(R.id.fragcon, fl);
fragmentTransaction.commit();
}
and use setArgument to pass bundle without interrupting the fragment life cycle
// use this it will work sure dude !!
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final FragmentLogin fl = new FragmentLogin();
final FragmentRegistration fr = new FragmentRegistration();
final android.support.v4.app.FragmentManager fragmentManager =
getSupportFragmentManager();
final android.support.v4.app.FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragcon, fr);
fragmentTransaction.commit();
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment = null;
Class fragmentClass = null;
if(fl.isVisible())
{
fragmentClass = FragmentRegistration.class;
}
else {
fragmentClass = FragmentLogin.class;
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getSupportFragmentManager();
String backStateName = fragment.getClass().getName();
boolean fragmentPopped = fragmentManager.popBackStackImmediate
(backStateName, 0);
if (!fragmentPopped && fragmentManager.findFragmentByTag(backStateName) ==
null){ //fragment not in back stack, create it.
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.flContent, fragment, backStateName);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();
}
}
});
}
}
if(fl.isVisible())
{
//put your argument like this
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
fr.setArguments(args)
fragmentManager.beginTransaction().replace(R.id.fragcon, fr);
fragmentTransaction.commit();
}else{
//put your argument like this
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
fr1.setArguments(args)
fragmentManager.beginTransaction().replace(R.id.fragcon, fl);
fragmentTransaction.commit();
}
i have encountred this problem and performed folowing solution to fix it but couldnt fix this problem yet. And also i tried to use fragmentpageradapter instead of fragmentstatepageradapterbut still facing same problem.
java.lang.IllegalStateException: Fragement no longer exists for key f1: index 3
this crash happens when i go back to fragment which contains viewpager.
Any idea?
firstly pushing productdetail fragment to "maincontainer"
public void switchToProductDetail(SearchHelper searchHelper, Product product)
{
ProductDetailFragment productDetailFragment = new ProductDetailFragment();
productDetailFragment.product = product;
productDetailFragment.searchHelper = searchHelper;
setNewFragment(productDetailFragment, R.id.mainContainer, "ProductDetail", true, true, true, true);
}
and then if user doesnt sign in and pressed to add to fav button, i am pushing signup fragment to "window" container.
public void switchtoSignIn(SignInSignUpFragment.SignInCompleteCallBack callBack)
{
SignInSignUpFragment signInSignUpFragment = new SignInSignUpFragment();
signInSignUpFragment.callBack = callBack;
setNewFragment(signInSignUpFragment, R.id.windowFL, "SignIn", true, true, true, true);
}
And the mainactivity xml(which contains the maincontainer and windowFL)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/windowFL"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:id="#+id/headerContainer" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/mainContainer"/>
</LinearLayout>
<LinearLayout
android:id="#+id/left_menu_frame"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_marginRight="#dimen/menumargin"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#ffffff" />
</android.support.v4.widget.DrawerLayout>
setnewfragment method is:
#SuppressLint("CommitTransaction")
public void setNewFragment(final Fragment fragment, final int containerId, final String tag, final boolean shouldAddBackStack, final boolean shouldReplace, final boolean shouldAnimation, final boolean shouldDrawerClose) {
if(isAnyMenuOpen() && shouldDrawerClose)
{
drawerLayout.closeDrawer(GravityCompat.START, true);
drawerClosedCallBack = new DrawerClosedCallBack() {
#Override
public void onDrawerClosed() {
setNewFragment(fragment, containerId, tag, shouldAddBackStack, shouldReplace, shouldAnimation, false);
}
};
return;
}
if (fragmentManager == null)
{
fragmentManager = getSupportFragmentManager();
}
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (shouldAnimation)
{
if(fragment instanceof SignInSignUpFragment)
{
fragmentTransaction.setCustomAnimations(R.anim.slide_in_bottom, R.anim.fade_out, R.anim.fade_in, R.anim.slide_out_bottom);
}
else
{
fragmentTransaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right);
}
}
if (shouldReplace)
{
fragmentTransaction.replace(containerId, fragment);
}
else
{
fragmentTransaction.add(containerId, fragment);
}
if(shouldAddBackStack)
{
fragmentTransaction.addToBackStack(tag);
}
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.commitAllowingStateLoss();
}
My current Android application has two Fragments:-
ListFragment
Detailfragment
My Layout XML resembles:-
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_anchorGravity="bottom"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
</FrameLayout>
I display the ListFragment first as follows:-
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(containerId, mListFragment, LIST_FRAGMENT_TAG);
if (mLandscape) {
} else {
fragmentTransaction.addToBackStack(LIST_FRAGMENT_TAG);
}
fragmentTransaction.commit();
When the user clicks on a List item, I want to hide the List so that I keep the current list position etc.. and display the detailFragment.
Heres the code I use to perform this UI change:-
mDetailFragment = new DetailFragment();
final Bundle fragmentArguments = new Bundle();
fragmentArguments.putString(ITEM_KEY, item.getKey());
mDetailFragment.setArguments(fragmentArguments);
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (mLandscape) {
fragmentTransaction.replace(containerId, mDetailFragment, DETAIL_FRAGMENT_TAG);
} else {
fragmentTransaction.hide(mListFragment);
fragmentTransaction.add(containerId, mDetailFragment, DETAIL_FRAGMENT_TAG);
}
fragmentTransaction.commit();
The above code all works fine and I can transition between the List and Detail Fragments successfully.
The issue I have is that when the user presses the BACK BUTTON on the detail Fragment to return to the ListFragment they return to a blank screen.
I have this code in my Activity to remove the detail fragment and show the hidden List fragment:-
#Override
public void onBackPressed() {
if (mLandscape) {
} else {
if (mListFragment.isHidden()) {
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(mDetailFragment);
fragmentTransaction.show(mListFragment);
fragmentTransaction.commit();
}
}
super.onBackPressed();
}
Why is fragmentTransaction.show(mListFragment); not showing the hidden ListFragment?
NOTE: So that I always rebuild my ui completely on orientation changes I have passed a null bundle to super.onCreate(savedInstanceStateNull);
private final Bundle savedInstanceStateNull = null;
private boolean mLandscape = false;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceStateNull);
setContentView(R.layout.activity_article_list);
mLandscape = getResources().getBoolean(R.bool.landscape);
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
manageFragments();
}
Heres how I fixed this issue:-
First remove my overriden onBackPressed()
Change display ListFragment to this:-
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(containerId, mListFragment, LIST_FRAGMENT_TAG);
fragmentTransaction.commit();
Change display detailFragment to this:-
mDetailFragment = new DetailFragment();
final Bundle fragmentArguments = new Bundle();
fragmentArguments.putString(ITEM_KEY, item.getKey());
mDetailFragment.setArguments(fragmentArguments);
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (mLandscape) {
fragmentTransaction.replace(containerId, mDetailFragment, DETAIL_FRAGMENT_TAG);
} else {
fragmentTransaction.hide(mListFragment);
fragmentTransaction.add(containerId, mDetailFragment, DETAIL_FRAGMENT_TAG);
fragmentTransaction.addToBackStack(DETAIL_FRAGMENT_TAG);
}
fragmentTransaction.commit();
EDIT: The problem below occurs on my Samsung Galaxy S3, however, when I run the same app on my Sony Xperia Z3+ it doesn't display the WIFI list at all. :-/
I have a weird situation with my app. I currently have five different fragments. All of them work as expected when doing FragmentTransactions except for one.
Initially, when I started my app I used one of the Android Studio templates, but this seemed like serious overkill as it used Fragments instead of a ListView for listing my WIFI items. It's been a while since I've developed anything with Android, so I'm playing catch-up.
I left the code in place and carried on developing the interface. The trouble came along when I eventually decided to remove the code that populated the main container with Fragment "items" and replace it with a Fragment containing a ListView.
All my Fragments work as expected and are replaced as expected when I select a new item from the menu except this new ListView Fragment, which remains in the background once I select it.
After I select it, if I select other Fragments they change as they should, but this first one stays in place.
The closest question I've found to my situation is this one, but it didn't help me.
This is what my screen looks like after selecting the problem Fragment and another Fragment:
My MainActivity onCreate() method:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
setupWifiScan();
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Scanning for devices...", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
scanForNetworks(view);
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
if(findViewById(R.id.fragment_container) != null){
if(savedInstanceState != null){
return;
}
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
WifiFragment wifiFragment = new WifiFragment();
wifiFragment.setArguments(getIntent().getExtras());
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragment_container, wifiFragment);
transaction.commit();
}else{
Log.i("MAIN_ACTIVITY", "fragment_container is NULL");
}
}
My MainActivity onNavigationItemSelected() method:
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_settings) {
GeneralSettings generalSettings = new GeneralSettings();
Bundle args = new Bundle();
args.putInt(GeneralSettings.ARG_POSITON, 0);
generalSettings.setArguments(args);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragment_container, generalSettings);
transaction.addToBackStack(null);
int stackId = transaction.commit();
Log.i(this.getClass().getSimpleName(), "Stack ID: " + stackId);
}else if(id == R.id.nav_wlan_setting){
WifiSettings wifiSettings = new WifiSettings();
Bundle args = new Bundle();
args.putInt(GeneralSettings.ARG_POSITON, 0);
wifiSettings.setArguments(args);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragment_container, wifiSettings);
transaction.addToBackStack(null);
int stackId = transaction.commit();
Log.i(this.getClass().getSimpleName(), "Stack ID: " + stackId);
}else if(id == R.id.nav_led_settings){
UvLedSettings uvLedSettings = new UvLedSettings();
Bundle args = new Bundle();
args.putInt(GeneralSettings.ARG_POSITON,0);
uvLedSettings.setArguments(args);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragment_container, uvLedSettings);
transaction.addToBackStack(null);
int stackId = transaction.commit();
Log.i(this.getClass().getSimpleName(), "Stack ID: " + stackId);
}else if(id == R.id.nav_server_settings){
ServerSettings serverSettings = new ServerSettings();
Bundle args = new Bundle();
// TODO: Fix Args Settings for all Fragments
args.putInt(GeneralSettings.ARG_POSITON, 0);
serverSettings.setArguments(args);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragment_container, serverSettings);
transaction.addToBackStack(null);
int stackId = transaction.commit();
Log.i(this.getClass().getSimpleName(), "Stack ID: " + stackId);
} else if (id == R.id.nav_current_device) {
} else if (id == R.id.nav_available_devices){
WifiFragment wifi = new WifiFragment();
Bundle args = new Bundle();
args.putInt(GeneralSettings.ARG_POSITON, 0);
wifi.setArguments(args);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragment_container, wifi);
transaction.addToBackStack(null);
int stackId = transaction.commit();
Log.i(this.getClass().getSimpleName(), "Stack ID: " + stackId);
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
The problem Fragment:
package com.myapp.serviceapplication.fragments;
import android.content.Context;
import android.net.wifi.ScanResult;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.RelativeLayout;
import com.myapp.serviceapplication.R;
import com.myapp.serviceapplication.adapters.WifiItemListAdapter;
import java.util.ArrayList;
/**
* A fragment representing a list of Items.
* <p>
* Activities containing this fragment MUST implement the {#link OnListFragmentInteractionListener}
* interface.
*/
public class WifiFragment extends Fragment {
// TODO: Customize parameter argument names
private static final String ARG_COLUMN_COUNT = "column-count";
// TODO: Customize parameters
private int mColumnCount = 1;
private OnListFragmentInteractionListener mListener;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public WifiFragment() {
// Required empty public constructor
}
// TODO: Customize parameter initialization
#SuppressWarnings("unused")
public static WifiFragment newInstance(int columnCount) {
WifiFragment fragment = new WifiFragment();
Bundle args = new Bundle();
args.putInt(ARG_COLUMN_COUNT, columnCount);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_wifi_list, container, false);
if(view instanceof RelativeLayout){
Context context = view.getContext();
RelativeLayout relativeLayout = (RelativeLayout) view;
ListView listView = (ListView) relativeLayout.findViewById(R.id.lst_wifi_items);
listView.setAdapter(new WifiItemListAdapter(this.getContext(), new ArrayList<ScanResult>()));
}
return view;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
// TODO: This needs to be modified to the correct listener type
if (context instanceof OnListFragmentInteractionListener) {
mListener = (OnListFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnListFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnListFragmentInteractionListener {
// TODO: Update argument type and name
void onListFragmentInteraction(View item);
}
}
The problem Fragment layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.WifiFragment"
>
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/lst_wifi_items"
android:background="#ffffff"/>
</RelativeLayout>
The content_main.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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".activities.MainActivity"
tools:showIn="#layout/app_bar_main">
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
The activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 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:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
I've spent too many hours trying to figure this out, but I just can't see the issue.
That's happen because your fragment container is above the listview and by default if you not use background in a ViewGroup(LinearLayout, RelativeLayout,...) then that's gonna be transparent, so, all you need do is put a background in your fragment container:
fragment_wifi_list.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.WifiFragment"
android:background="#ffffff"
>
...
TIP:
android:clickable="true"
That's avoid concurrence clicks problems
Add the following lines to the top relative layout of problematic fragment
android:background="#ffffff"
android:clickable="true"
Hope it works.
I just started with fragment design for HoneyComb. I created two fragments. When i click a button in the left side fragment, a new fragment is created in right side. Meanwhile when i click a button in the right fragment(ie. DetialsFragment in my code below should be replaced by another fragment.
main.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"
android:orientation="horizontal" >
<fragment class="com.fragment.example.Titles"
android:id="#+id/titles" android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
<FrameLayout android:id="#+id/details" android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
</LinearLayout>
FragmentExample.java
public class FragmentExample extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Titles.java
public class Titles extends Fragment {
public FragmentTransaction ft;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.main1, null);
Button button1 = (Button)v.findViewById(R.id.button1);
button1.setText("santhosh");
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
DetailsFragment details = (DetailsFragment)
getFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != 1) {
// Make new fragment to show this selection.
details = DetailsFragment.newInstance(1);
// Execute a transaction, replacing any existing
// fragment with this one inside the frame.
ft
= getFragmentManager().beginTransaction();
ft.add(R.id.details, details, "detail");
ft.setTransition(
FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
}
});
return v;
}
}
DetailsFragment.java
public class DetailsFragment extends Fragment {
/**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
Titles title = new Titles();
String[] titles = {"Title1", "Title2", "Title3", "Title4"};
public static DetailsFragment newInstance(int index) {
DetailsFragment f = new DetailsFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
// Currently in a layout without a container, so no
// reason to create our view.
return null;
}
Button button = new Button(getActivity());
button.setText("Next");
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
return button;
}
}
Then provided your button is showing and the click event is being fired you can call the following in your click event:
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.details, new NewFragmentToReplace(), "NewFragmentTag");
ft.commit();
and if you want to go back to the DetailsFragment on clicking back ensure you add the above transaction to the back stack, i.e.
ft.addToBackStack(null);
Or am I missing something? Alternatively some people suggest that your activity gets the click event for the button and it has responsibility for replacing the fragments in your details pane.
Latest Stuff
Okay. So this is a very old question and has great answers from that time. But a lot has changed since then.
Now, in 2020, if you are working with Kotlin and want to change the fragment then you can do the following.
Add Kotlin extension for Fragments to your project.
In your app level build.gradle file add the following,
dependencies {
def fragment_version = "1.2.5"
// Kotlin
implementation "androidx.fragment:fragment-ktx:$fragment_version"
// Testing Fragments in Isolation
debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
}
Then simple code to replace the fragment,
In your activity
supportFragmentManager.commit {
replace(R.id.frame_layout, YourFragment.newInstance(), "Your_TAG")
addToBackStack(null)
}
References
Check latest version of Fragment extension
More on Fragments
You can try below code. it’s very easy method for push new fragment from old fragment.
private int mContainerId;
private FragmentTransaction fragmentTransaction;
private FragmentManager fragmentManager;
private final static String TAG = "DashBoardActivity";
public void replaceFragment(Fragment fragment, String TAG) {
try {
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(mContainerId, fragment, tag);
fragmentTransaction.addToBackStack(tag);
fragmentTransaction.commitAllowingStateLoss();
} catch (Exception e) {
// TODO: handle exception
}
}
Use android.support.v4.app for FragmentManager & FragmentTransaction in your code, it has worked for me.
DetailsFragment detailsFragment = new DetailsFragment();
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.details,detailsFragment);
fragmentTransaction.commit();
If you have a handle to an existing fragment you can just replace it with the fragment's ID.
Example in Kotlin:
fun aTestFuction() {
val existingFragment = MyExistingFragment() //Get it from somewhere, this is a dirty example
val newFragment = MyNewFragment()
replaceFragment(existingFragment, newFragment, "myTag")
}
fun replaceFragment(existing: Fragment, new: Fragment, tag: String? = null) {
supportFragmentManager.beginTransaction().replace(existing.id, new, tag).commit()
}
Updated Answer (Working for Overlap problem as well)
#aniket-thakur(https://stackoverflow.com/users/2396539/aniket-thakur) gave correct answer. Thank you for that!
But, getFragmentManager() is deprecated, so following code did work for me.
final FragmentTransaction ft = getParentFragmentManager().beginTransaction();
ft.replace(R.id.nav_host_fragment, new GalleryFragment(), "NewFragmentTag");
ft.addToBackStack(null);
ft.commit();
it's very simple how to replace with Fragment.
DataFromDb changeActivity = new DataFromDb();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.changeFrg, changeActivity);
transaction.commit();