I can not understand with the fragments and BackStack - android

I have aсivity with one button and frame:
<?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"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="new fragment"
android:id="#+id/replaceFragment" android:layout_gravity="center_horizontal"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="fill_parent" android:layout_gravity="center_horizontal" android:id="#+id/contentFrame">
</FrameLayout>
</LinearLayout>
code:
public class MyActivity extends Activity implements View.OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button replaceBtn = (Button) findViewById(R.id.replaceFragment);
replaceBtn.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.replaceFragment:
Fragment fragment1 = new Frag1();
FragmentTransaction fTrans = getFragmentManager().beginTransaction();
fTrans.replace(R.id.contentFrame, fragment1);
fTrans.commit();
break;
}
}
}
button is pressed, etc. I create a fragment:
public class Frag1 extends Fragment implements View.OnClickListener {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag1, null);
Button replaceBtn2 = (Button) v.findViewById(R.id.replaceFragment2);
replaceBtn2.setOnClickListener(this);
return v;
}
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.replaceFragment2:
Frag2 fragment2 = new Frag2();
FragmentTransaction fTrans = getFragmentManager().beginTransaction();
fTrans.replace(R.id.contentFrame,fragment2);
fTrans.commit();
break;
}
}
}
it also has a button which when pressed I create fragment2:
public class Frag2 extends Fragment implements View.OnClickListener {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag2, null);
Button replaceBtn3 = (Button) v.findViewById(R.id.replaceFragment3);
replaceBtn3.setOnClickListener(this);
return v;
}
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.replaceFragment3:
Frag3 fragment3 = new Frag3();
FragmentTransaction fTrans = getFragmentManager().beginTransaction();
fTrans.replace(R.id.contentFrame,fragment3);
fTrans.commit();
break;
}
}
}
fragment2 also creates a new fragment3:
public class Frag3 extends Fragment{
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag3, null);
return v;
}
}
if I do when creating each fragment will add a line:
fTrans.addToBackStack(null);
then later when I press the "back" button on the screen will appear the fragments in reverse order. but I want to when I'm in fragmente3 when you press the "back" appears immediately fragment1.
if I do not add the line fTrans.addToBackStack(null); in fragment2 they overlap.

in order to do that, you can keep the fragments backStack references in your activity or for example onBackPressed you could try something like below:
if (getSupportFragmentManager().getBackStackEntryCount() != 0) {
//back to fragment 1.
}

Here you are a function which I use for one of my projects. I implemented it in the parent of the Activity that manages the fragments. I don't know if I'm going to clarify anything about the behaviour because all you tell us in you question make sense to me.
I my case, it was a simple app (almost static), but it changes fragments and, as you want to, many times I want to go back two fragment in "history" so I think it could help.
#Override
public void replaceFragment(FRAGMENT_TYPE destinyFragmentType, int fragmentContainerID, boolean addToBackStack) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
Fragment currentFragment = FragmentFactory.getFragment(destinyFragmentType);
fragmentTransaction.replace(fragmentContainerID, currentFragment);
if (addToBackStack) {
fragmentTransaction.addToBackStack(null);
}
fragmentTransaction.commit();
}
Notes:
The second parameter is the parameter that indicates if you want to
keep in history or not. For your case: frg1 -> fr2 : param true; fr2
-> fr3 : param false;
I used a Factory in order to get a cleaner code, but you can use
whatever you want, change the header, give the function your fragment
etc.
I hope this helps!!

Related

App title doesn't change after returning to previous fragment

I've been developing an android app which I included the default Navigation-Drawer from Android Studio and so on. In my home fragment, I've implemented CarViews, and then set those cardview(s) OnClickListener to replace the fragment with traditional procedure.
After the fragment replacement and new page comes, I wanted to change the Actionbar title.
So in the onCreateView(...) method, I tried,
((AppCompatActivity)getActivity()).getSupportActionBar().setTitle("B");
It worked. But after pressing the hardware back button to go back to the stacked fragment, the title remains changed & it doesn't change to "Home" again. I've tried other ways. Here's my following codes. Thanks in advance.
public class HomeFragment extends Fragment implements View.OnClickListener {
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_home, container, false);
Objects.requireNonNull(((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar()).setTitle("Home");
CardView cardView1 = root.findViewById(R.id.doctor_on);
CardView cardView2 = root.findViewById(R.id.ambulance_e);
CardView cardView3 = root.findViewById(R.id.maintainance_s);
cardView1.setOnClickListener(this);
cardView2.setOnClickListener(this);
cardView3.setOnClickListener(this);
return root;
}
#Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.doctor_on:
FragmentTransaction fragmentTransaction = Objects.requireNonNull(getActivity()).getSupportFragmentManager().beginTransaction();
Fragment fragment1 = new doctors();
fragmentTransaction.replace(R.id.container1, fragment1).addToBackStack(getString(R.string.menu_home)).commit();
return;
case R.id.ambulance_e:
//Put Actions
FragmentTransaction fragmentTransaction2 = Objects.requireNonNull(getActivity()).getSupportFragmentManager().beginTransaction();
Fragment fragment2 = new ambulance();
fragmentTransaction2.replace(R.id.container1, fragment2).addToBackStack(getString(R.string.menu_home)).commit();
return;
case R.id.maintainance_s:
//Put Actions
FragmentTransaction fragmentTransaction3 = Objects.requireNonNull(getActivity()).getSupportFragmentManager().beginTransaction();
Fragment fragment3 = new maintanance();
fragmentTransaction3.replace(R.id.container1, fragment3).addToBackStack(getString(R.string.menu_home)).commit();
return;
}
}
#Override
public void onResume() {
super.onResume();
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle("Home");
}
}
To the next fragment(where I change the titlebar and pressed back button):
public class doctors extend Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
((AppCompatActivity)getActivity()).getSupportActionBar().setTitle("B");
View root = inflater.inflate(R.layout.fragment_doctors, container, false);
return root;
}
}
And in the doctors Fragment... Should fix the title error.
#Override
public void onDestroyView() {
super.onDestroyView();
Objects.requireNonNull(((AppCompatActivity) Objects.requireNonNull(getActivity()))
.getSupportActionBar())
.setTitle(getString(R.string.your_title_here));
}
You have to override the method onBackPressed() and write the code:
#Override
public View onBackPressed(){
//Here goes the code that head back to your main fragment
FragmentTransaction fragmentTransaction3 = Objects.requireNonNull(getActivity()).getSupportFragmentManager().beginTransaction();
Fragment fragment3 = new maintanance();
fragmentTransaction3.replace(R.id.container1, fragment3).addToBackStack(getString(R.string.menu_home)).commit();
}
}`
Add below code in Home Fragment...
#Override
public void onHiddenChanged(Boolean hidden) {
super.onHiddenChanged(hidden);
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle("Home");
}

Resume the fragment in android:

To resume the fragment press on backpress.On Backpress resume fragment in android.
I have the navigation drawer.fragment has replace from one layout to another.
On back press want resume the fragment.
To resume the fragment:
public class ResumeFragment extends Fragment {
View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.puser_registration, null);
Button btn_ok=(Button)view.findViewById(R.id.btn_ok);
EditText edit_text=(EditText)view.findViewById(R.id.edit_text);
btn_ok.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Ticket_generation fragment = new Ticket_generation();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.drcontent_frame, fragment, "Second");
fragmentTransaction.commit();
}
});
return view;
}}
This fragment to resume in android.On back press resume the fragment in android.The edit edit value to stored.
Try this to add below attribute in EditText in XML.
<EditText
...
android:freezesText="true"
/>

Fragment wont start - called from Activity

I'm trying to start a fragment from my main activity, but somehow the fragment is not showing up. Can someone help me with this?
Here is my code:
public class Main extends Activity implements OnClickListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button b = (Button) findViewById(R.id.action_menu);
b.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v.getId()==R.id.action_menu){
Log.d("--", "menu clicked");
MenuFragment newFragment = new MenuFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(android.R.id.content, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
main activity layout:
<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:id="#+id/main_rl" >
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="#+id/action_menu" android:text="Menu"/>
</RelativeLayout>
and my fragment Class:
public class MenuFragment extends Fragment{
final String TAG=this.getClass().getSimpleName();
private GridView grid;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View mView;
Log.d(TAG, "Hello from Fragment");
mView=inflater.inflate(R.layout.menu_fullscreen, null);
initWidgets(mView);
return mView;
}
private void initWidgets(View mView) {
grid=(GridView) mView.findViewById(R.id.menu_fullscreen_grid);
}
}
you cannot replace what you put in setContentView(R.layout.main); if main.xml is hardCoded...(xml file). with
transaction.replace...
You may use fragmentActivity without setContentView(R.layout.main)

fragments overlap each other by pressing the back

I have akivity with one button and frame:
public class MyActivity extends Activity implements View.OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button replaceBtn = (Button) findViewById(R.id.replaceFragment);
replaceBtn.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.replaceFragment:
Fragment fragment1 = new Frag1();
FragmentTransaction fTrans = getFragmentManager().beginTransaction();
fTrans.replace(R.id.contentFrame, fragment1);
**fTrans.addToBackStack(null);**
fTrans.commit();
break;
}
}
}
button is pressed, etc. I create a fragment:
public class Frag1 extends Fragment implements View.OnClickListener {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag1, null);
Button replaceBtn2 = (Button) v.findViewById(R.id.replaceFragment2);
replaceBtn2.setOnClickListener(this);
return v;
}
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.replaceFragment2:
Frag2 fragment2 = new Frag2();
FragmentTransaction fTrans = getFragmentManager().beginTransaction();
fTrans.replace(R.id.contentFrame,fragment2);
**fTrans.addToBackStack(null);**
fTrans.commit();
break;
}
}
}
it also has a button which when pressed I create fragment2:
public class Frag2 extends Fragment implements View.OnClickListener {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag2, null);
Button replaceBtn3 = (Button) v.findViewById(R.id.replaceFragment3);
replaceBtn3.setOnClickListener(this);
return v;
}
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.replaceFragment3:
Frag3 fragment3 = new Frag3();
FragmentTransaction fTrans = getFragmentManager().beginTransaction();
fTrans.replace(R.id.contentFrame,fragment3);
**//do not add backstack**
fTrans.commit();
break;
}
}
}
fragment2 also creates a new fragment3:
public class Frag3 extends Fragment{
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag3, null);
return v;
}
}
then later when I press the "back" button on the screen will appear the fragments in reverse order. but I want to when I'm in fragmente3 when you press the "back" appears immediately fragment1.
that is because you don't added the fragment2 to backstack. The fragment wont be pop back or disappear when they excluded from backstack. backstack runs exactly as activity back stack or any other stack container works.
to explain better:
added first fragment to stack
[stack] topElement Fragment1 (is showing)
added 2nd but did not add to the stack [stack] topElement
Fragment1(is not showing)
added 3rd fragment to stack [stack] topElement Fragment3(is
showing)
now if you pop it will return in this order : 3rd,1st and nothing more.
EDIT
in this case you can simply override the onBackPressed() like this to achieve the behaviour you want:
onBackPressed(){
//default back pressed behaviour
if(mFragmentManager.getBackStackEntryCount()==0)//you can set it ==1 if you wish to close
finish();
mFragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}

Destroyed fragment recreated and redestroyed when restarting the app

I'm trying do understand the lifecycle of Fragment.
I have a MainActivity, with a layout including two FrameLayout to load Fragments, one for a top bar with a vertical menu, another one for the content.
When I start the app, an instance of HomeFragment is loaded in the content FrameLayout container. Then when I click on a button in the menu, an instance of SomeFragment replaces it.
When on the SomeFragment content, I click on the device's Home button, and all the visible Fragment (i.e. the TopBarFragment and the SomeFragment) are destroyed and detached from the MainActivity, i.e. onDestroyView, onDestroy and onDetach are called for both.
Now when I restart the app, the TopBarFragment and the SomeFragment are created and destroyed (full lifecycle from onAttach to onDetach) and then the TopBarFragment and the HomeFragment are created, as expected from the code in the MainActivity's onCreate.
Why are the TopBarFragment and the SomeFragment, i.e. the latest visible Fragment before clicking on the device's Home button, recreated and destroyed before executing what's in the MainActivity's onCreate?
Note: in order to test my app I checked the option Don't keep activities in my device's developer options.
MainActivity.java
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
Fragment homeFragment = new HomeFragment();
fragmentTransaction.replace(R.id.content_container, homeFragment, "");
Fragment topBarFragment = new TopBarFragment();
fragmentTransaction.replace(R.id.top_bar_container, topBarFragment, "top_bar_fragment");
fragmentTransaction.commit();
}
}
main.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" >
<FrameLayout
android:id="#+id/content_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="44dp" />
<FrameLayout
android:id="#+id/top_bar_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false" />
</RelativeLayout>
TopBarFragment.java
public class TopBarFragment extends Fragment{
private int mSelectedMenuOption = 0;
private LinearLayout mVerticalMenu;
private Boolean mMenuIsOpen = true;
private ImageButton btn_01, btn_02; // there are more
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.top_bar, container, false);
}
#Override
public void onActivityCreated (Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
btn_01 = (ImageButton) getView().findViewById(R.id.btn_01);
btn_02 = (ImageButton) getView().findViewById(R.id.btn_02);
btn_01.setOnClickListener(mButtonClickListener);
btn_02.setOnClickListener(mButtonClickListener);
mVerticalMenu = (LinearLayout) getView().findViewById(R.id.vertical_menu);
toggleMenu(0);
Button btn_menu = (Button) getView().findViewById(R.id.btn_menu);
btn_menu.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// toggle vertical menu
}
});
}
private OnClickListener mButtonClickListener = new OnClickListener()
{
#Override
public void onClick(View v) {
/* ... */
if(!v.isSelected()){
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
switch(v.getId()){
case R.id.btn_01:
Fragment homeFragment = new HomeFragment();
fragmentTransaction.replace(R.id.content_container,homeFragment, "");
fragmentTransaction.commit();
break;
case R.id.btn_02:
Fragment someFragment = new SomeFragment();
fragmentTransaction.replace(R.id.content_container, someFragment, "");
fragmentTransaction.commit();
break;
}
}
}
};
}
SomeFragment
public class SomeFragment extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
((TopBarFragment)getActivity().getSupportFragmentManager().findFragmentByTag("top_bar_fragment")).setSelectedButton(1);
return inflater.inflate(R.layout.some_fragment, container, false);
}
}

Categories

Resources