I have one fragment in an activity, I can launch the fragment using FragmentManager and FragmentTransaction, but when I try to navigate back to the Activity via the back button, the app exits.
Here is my fragment creation & transaction in the Activity class:
DetailFragment df = new DetailFragment();
try {
df.initFragment(jsonObject);
} catch (Exception e) {
e.printStackTrace();
}
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, df);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
I also override onBackPressed()
#Override
public void onBackPressed() {
super.onBackPressed();
}
With the above setup, one press of the back button exits to the home screen.
I also tried to modify onBackPressed() to do:
#Override
public void onBackPressed(){
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
} else {
super.onBackPressed();
}
}
On this second version of onBackPressed(), it takes 2 back presses to go back to the home screen. Keep in mind I am trying to return to the original Activity.
Any suggestions?
P.S. I can add my fragment code if needed
Your second version of onBackPressed() requires 2 back presses to go back to the home screen. So it seems like fm.popBackStack() is getting called. Try replacing it with popBackStackImmediate().
Edit:
When you are creating the fragment, try using the following instead of .replace:
fragmentTransaction.add(R.id.fragment_container, df);
If that still doesn't work, try:
#Override
public void onBackPressed(){
FragmentManager fm = getFragmentManager();
if (df.isVisible) {
fm.beginTransaction().remove(df).commit();
} else {
super.onBackPressed();
}
}
(although this is less desirable as you are hard-coding what to remove).
The navigation was working, but in my Fragment's onCreateView I used setContentView() to the fragment view which painted the fragment view to the main activity, so it appeared that the back button would exit out if it was pressed twice, but it was actually returning to the main activity as it should, it just repainted the main activity so it wasnt possible to tell.
Thanks for the help #RogueBaneling !!
original code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.fragment_detail, container, false);
fragmentView.setClickable(true);
getActivity().setContentView(R.layout.fragment_detail);
final TextView movieTitleText = (TextView) getActivity().findViewById(R.id.movie_title_text);
movieTitleText.setText(title);
// editing textView code...
return fragmentView;
}
into:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.fragment_detail, container, false);
fragmentView.setClickable(true);
final TextView movieTitleText = (TextView) fragmentView.findViewById(R.id.movie_title_text);
movieTitleText.setText(title);
// editing textView code...
return fragmentView;
}
Related
I tried to phrase the title as I can, but Basically inside the HomeActivity I have a custom menu with a bunch for fragments.! One of the them is HomeFragment which contains a Tablelayout of 2 tabs with a viewpager..!
Everything is working correctly.! but inside the menu fragment, when the user clicks the back button on the toolbar is to return to the HomeFragment.
A fragment replacement method will do the trick which I already used it to replace between the fragments when choosing from the menu !?
But in this case, the HomeFragment opens yet the Tablayout isn't responsive! it feels like the the fragment isn't created correctly!?
I tried using a new intent of the same activity which opens HomeFragment by default, and it opens it but with the same problem..!
The Problem
The Code
HomeFragment
// code..
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
InitViews(rootView);
TabLayoutAdapter adapter = new TabLayoutAdapter(getFragmentManager());
pager.setAdapter(adapter);
tabLayout.setupWithViewPager(pager);
return rootView;
}
// code..
Menu Fragment
// code..
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.to_home:
replaceFragment(new HomeFragment());
// tried this and it's the same problem
// startActivity(new Intent(getActivity(), HomeActivity.class).setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void replaceFragment(Fragment fragment) {
android.support.v4.app.FragmentTransaction t = getFragmentManager().beginTransaction();
t.replace(R.id.Container, fragment);
t.commit();
}
// code..
Looking at the code I think you have to use getChildFragmentManager() instead of getFragmentManager() and use it for fragment Transaction.
The definition of getChildFragmentManager() is:
Return a private FragmentManager for placing and managing Fragments inside of this Fragment.
And the definition of getFragmentManager() is:
Return the FragmentManager for interacting with fragments associated with this fragment's activity.
Replace this line of code having getFragmentManager() by getChildFragmentManager()
TabLayoutAdapter adapter = new TabLayoutAdapter(getChildFragmentManager());
Also in the menu Fragment
android.support.v4.app.FragmentTransaction t = getChildFragmentManager().beginTransaction();
I have a couple of fragments. But all the fragments lead to PeriodFragment when they press a button. My question is how do I implement so that when the user presses the BACK button on his mobile phone, the PeriodFragment will switch back to the fragment it was entered from.
This is the java code from PeriodFragment.java:
public class PeriodFragment extends Fragment {
Button btnPretrazi;
public PeriodFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_period, container, false);
//buttonPretraziPeriod
btnPretrazi = (Button) view.findViewById(R.id.buttonPretraziPeriod);
btnPretrazi.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getContext(),"test", Toast.LENGTH_SHORT).show();
}
});
return view;
}
}
This is my TvrdjavaFragment.java (one of the fragments that have the button to switch to PeriodFragment.java) :
package com.example.ivanp.msnis;
public class TvrdjavaFragment extends Fragment {
Button btnIdinaperiod;
public TvrdjavaFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_tvrdjava, container, false);
// Inflate the layout for this fragment
//show date
TextView datumprikaz = (TextView) view.findViewById(R.id.datumprikaz);
Date danas = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
String novDatum = sdf.format(danas);
datumprikaz.setText(novDatum);
//End of show date
btnIdinaperiod = (Button) view.findViewById(R.id.buttonIdinaperiod);
btnIdinaperiod.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PeriodFragment periodFragment = new PeriodFragment();
FragmentTransaction periodFragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
periodFragmentTransaction.replace(R.id.frame, periodFragment);
periodFragmentTransaction.commit();
}
});
return view;
}
}
I'm new to android studio, so please tell the details.
According to android docs When using fragments in your app, individual FragmentTransaction objects may represent context changes that should be added to the back stack. For example, if you are implementing a master/detail flow on a handset by swapping out fragments, you should ensure that pressing the Back button on a detail screen returns the user to the master screen. To do so, call addToBackStack() before you commit the transaction:
// Works with either the framework FragmentManager or the
// support package FragmentManager (getSupportFragmentManager).
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail")
// Add this transaction to the back stack
.addToBackStack()
.commit();
Adding to backstack will solve the problem:
periodFragmentTransaction.replace(R.id.frame, periodFragment);
periodFragmentTransaction.addToBackStack(null);
periodFragmentTransaction.commit();
I'm really sorry for this stupid question but I've been reading various things but seems can't get through my thick skull. I'm really desperate here so please bear with me.
So I got one fragment full of text, say fragment_chapter_1.xml. One of the text need further explanation so I want to make it when the text (Copyright Act (Amendment) 1997) got clicked (it is not set clickable in xml layout), it will go to fragment_explain_law.xml.
The fragment_explain_law.xml have a TextView explainLaw, which will get setText (in ExplainLawFragment.java) to it's own explanation of the text clicked in fragment_chapter_1.xml. I use this way because if other text got clicked, it will reuse the same fragment_explain_law.xml but the explainLaw will set to different explanation.
Here's the code.
In Chapter1Fragment.java, it will view fragment_chapter_one.xml. law1 is id for Copyright Act (Amendment) 1997.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_chapter_1, container, false);
law1 = (TextView) rootView.findViewById(R.id.law1);
law1.setOnClickListener(this);
// Inflate the layout for this fragment
return rootView;
}
When law1 got clicked, fragment_explain_law.xml will be shown. For that, I make it by go to ExplainLawFragment.java (am I doing it right?).
#Override
public void onClick(View v) {
// when law1 till law11 clicked, go to ExplainLawFragment.java to view fragment_explain_law.xml
Fragment fragment = null;
String title = null;
switch (v.getId()) {
case R.id.law1:
// view explainLaw
fragment = new ExplainLawFragment();
title = "Copyright Act (Amendment) 1997";
break;
}
}
In ExplainLawFragment.java
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_explain_law, container, false);
explainLaw = (TextView) rootView.findViewById(R.id.explainLaw);
explainLaw.setText("blahblahblah");
// Inflate the layout for this fragment
return rootView;
}
Result: Nothing happen.
Logcat when I click law1: V/SettingsInterface: from settings cache , name = sound_effects_enabled , value = 1
Where did I go wrong? Please help.
You can call second fragment like this....
#Override
public void onClick(View v) {
// when law1 till law11 clicked, go to ExplainLawFragment.java to view fragment_explain_law.xml
Fragment fragment = null;
String title = null;
switch (v.getId()) {
case R.id.law1:
// view explainLaw
fragment = new ExplainLawFragment();
title = "Copyright Act (Amendment) 1997";
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
break;
}
Hope this will help you..
I tried to make an application that shows a fragment at start then you can change that fragment to an other one with a button in the first fragment. But when I put the button action in the fragments java, it won't start and I get the nullpointerexception error. Could you tell me why?
public class Fragment_main extends Fragment {
FragmentManager fm = getFragmentManager();
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Button button_inditas = (Button) getView().findViewById(R.id.button_inditas);
button_inditas.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fm.beginTransaction().replace(R.id.content_frame, new Fragment_1()).commit();
}
});
return inflater.inflate(R.layout.fragment_main,container,false);
}
}
But when I put the button action in the fragments java, it won't start and I get the nullpointerexception error. Could you tell me why?
Well I see some errors on your code...
First of all you can't call getView() if you haven't inflated one, it means that you MUST inflate a view as i'll put on my answer and then you can avoid the getView() and use that view itself.
And instead of returning the inflater you have to return your View
This is how your Fragment should look like:
public class Fragment_main extends Fragment {
public Fragment_main() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main,container,false);
Button button_inditas = (Button)rootView.findViewById(R.id.button_inditas);
button_inditas.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fragmentManager = getFragmentManager ();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction ();
fragmentTransaction.add (R.id.content_frame, new Fragment_1());
fragmentTransaction.commit ();
});
return rootView;
}
}
You have to inflate the view first and use the view returned by that instead of getView ().
View view = inflater.inflate (...);
and then
... = (Button) view.findView(...);
This happens because the view that is returned by getView () hasn't been created yet, so getView() returns null.
I have two fragment, "A" and "B".
When I return (BackPressed) to my fragment "A", the values of edittext aren't refresh. Why?
I have this code to call fragment "B".
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_container_pedido_novo,
container, false);
btnAddProduto = (Button) view.findViewById(R.id.btnNovoProduto);
btnAddProduto.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Fragment fragment = new FragmentContainerProduto(true);
FragmentManager frgManager = getActivity()
.getSupportFragmentManager();
frgManager.beginTransaction()
.replace(R.id.content_frame, fragment)
.addToBackStack(null).commit();
}
});
edtCodPedido = (EditText) view.findViewById(R.id.edtCodPedidoNovo);
edtVlBruto = (EditText) view.findViewById(R.id.edtVlBrutoPedidoNovo);
edtCodPedido
.setText(String.valueOf(GlobalUtil.objPedido.getCodPedido()));
edtVlBruto.setText(String.valueOf(GlobalUtil.objPedido.getVlBruto()));
return view;
}
Someone?
When you return to a fragment from the back stack Android does not re-create the fragment but re-uses the same instance of it and starts with onCreateView() in the fragment lifecycle. The key thing is you should not inflate view again in onCreateView() of the fragment to which you return, because you are using the existing fragment instance. You need to save and reuse the rootView. See here the answer of Vince Yuan How can I maintain fragment state when added to the back stack?.
Well, I just need put this code...
#Override
public void onResume() {
super.onResume();
edtVlBruto.setText(String.valueOf(GlobalUtil.objPedido.getVlBruto()));
edtCodPedido
.setText(String.valueOf(GlobalUtil.objPedido.getCodPedido()));
}