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();
Related
I am trying to use Bundle to send data from an activity to a fragment. The activity is receiving the input from a dialogbox when the user clicks on the actionbar add icon. The button also opens the dialogbox but it sends the data straight to the fragment (I'm trying to learn the difference between activity and fragment and to interact with the dialogfragment). None of the solutions on the internet have worked for me, and I was hoping someone can help
I have provided a visualization to aid in my explanation of the issue. So initially, I click the action add icon that opens the dialogbox (2nd pic), when I enter an input, it doesn't alter the data on the fragment. Only when I press the action add icon for a second time, does the first input get updated (3rd pic). Also you may notice that it says "Bundle{[Dialog Input = First Input]}" where First Input is the user input. How do I change this to just, First Input. I tried clearing the textview before setting the value, but that doesn't work. Now lastly when I press the button, it opens the dialogbox and when I enter in data, the data from the action add icon (handled in activity then data sent to fragment) overlaps with the data from the button (data sent straight to fragment). Any help would be appreciated. Thanks in advance.
MainActivity:
public class MainActivity extends AppCompatActivity implements
MyCustomDialog.OnInputSelected{
public String dialogInput;
FragmentManager fragmentManager;
#Override
public void sendInput(String input) {
dialogInput = input;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentManager = getSupportFragmentManager();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
//Inflate the menu, this adds items to the action bar if it is present
getMenuInflater().inflate(R.menu.menu, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
//Handle action bar clicks here. The action bar will automatically handle clicks on the home/up button
//so long as you specify a parent activity in AndroidManifest.xml
switch(item.getItemId()){
case R.id.action_add:
MyCustomDialog dialog = new MyCustomDialog();
dialog.show(getSupportFragmentManager(), "MyCustomDialog");
//Trying Bundle to pass data, dialog input between activity and fragment
Bundle bundle = new Bundle();
bundle.putString("Dialog Input", dialogInput);
//Set Fragment class arguments
MainFragment fragment = new MainFragment();
fragment.setArguments(bundle); //set argument bundle to fragment
fragmentManager.beginTransaction().replace(R.id.MainFragment,fragment).commit(); //now replace Mainfragment
Toast.makeText(this, "Action_Add Clicked Successfully", Toast.LENGTH_SHORT).show();
}
return super.onOptionsItemSelected(item);
}
}
MainFragment:
public class MainFragment extends Fragment implements MyCustomDialog.OnInputSelected{
TextView InputDisplay;
Button OpenDialog;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
InputDisplay = view.findViewById(R.id.InputDisplay);
OpenDialog = view.findViewById(R.id.Open_Dialog);
//Getting Main Activity dialog information with Bundle, that was received from toolbar add
Bundle bundle = getArguments();
if(bundle != null){
String dialogInput = bundle.toString();
//Clearing since Fragment call and activity call overlap each other.
InputDisplay.setText("");
InputDisplay.clearComposingText();
InputDisplay.setText(dialogInput);
}
//String dialogInput = this.getArguments().getString("Dialog Input");
OpenDialog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d("MainFragment", "onClick: opening dialog");
MyCustomDialog customDialog = new MyCustomDialog();
customDialog.setTargetFragment(MainFragment.this, 1);
customDialog.show(getFragmentManager(), "MyCustomDialog");
}
});
return view;
}
#Override
public void sendInput(String input) {
InputDisplay.setText("");
InputDisplay.setText(input);
}
}
My Custom Dialog:
public class MyCustomDialog extends DialogFragment {
private EditText Input;
private TextView ActionOK, ActionCANCEL;
private OnInputSelected onInputSelected;
public interface OnInputSelected{
void sendInput(String input);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try{
Fragment onInputSelected_fragment = getTargetFragment();
Activity onInputSelected_activity = getActivity();
if(onInputSelected_fragment != null){
onInputSelected = (OnInputSelected) onInputSelected_fragment;
}else{
onInputSelected = (OnInputSelected) onInputSelected_activity;
}
//throw new RuntimeException("Custom Dialog onAttach Listener was NULL");
}catch(ClassCastException e){
Log.e("Custom Dialog", "onAttach: ClassCastException: " + e.getMessage());
}
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_my_custom, container, false);
Input = view.findViewById(R.id.Input);
ActionOK = view.findViewById(R.id.Action_OK);
ActionCANCEL = view.findViewById(R.id.Action_CANCEL);
ActionCANCEL.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getDialog().dismiss();
}
});
ActionOK.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onInputSelected.sendInput(Input.getText().toString());
getDialog().dismiss();
}
});
return view;
}
}
How do I change this to just, First Input.
your output is printed like this "Bundle{[Dialog Input = First Input]}" because you are directly doing bundle.toString(); instead of getting the value you have stored in the bundle.
change the above to this
String dialogInput = bundle.getString("Dialog Input")
InputDisplay.setText(dialogInput);
the data from the action add icon overlaps with the data from the button
Clear the existing text in the text view before setting the new value like this
String dialogInput = bundle.getString("Dialog Input")
InputDisplay.setText(");
InputDisplay.setText(dialogInput);
Also, I noticed that all the variable names that you have used are not following camel case I suggest you correct that as well.
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 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;
}
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()));
}
I am trying to add left side slide menu inside my application but i am facing little trouble getting the slide menu to the following child activities of the fragment.
So far i have tried using this sliding menu example and when i got this image now inside the "Find People" fragment class i have static data.
Find People (Parent Activity) on Button Click go to ---> Friends (Child Activity of Find People) on Button Click go to ----> Names (Child Activity of Friends)
I am trying to get the same sliding menu with the Child Activities also that i failed to achieve so far please can any one help me out
public class FindPeopleFragment extends Fragment {
public FindPeopleFragment(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_find_people, container, false);
Button btn = (Button) rootView.findViewById(R.id.butto);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), Friends.class);
startActivity(intent);
}
});
return rootView;
}
}
Friends (Child Activity)
public class Friends extends Activity {
Button btnNext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.friends_xml);
btnNext = (Button)findViewById(R.id.btnNexts);
btnNext.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
// Go to Names Child Activity
}
});
}
}
And Similarly Names (Child Activity)
How do i get the same slide menu in both the child activities (Friends & Names). Any idea ??
Plz help me out in this.
Code Snippet will be much helpful.
Thanks
As #Piyush Gupta said you need to call new Fragment instead of calling activities,
In Place of activity you need to use Fragment and move from one Fragment to next used this code
Instead of using Fragment element use Framelayout id of the fragment Xml
Replace ur code with this
public class FindPeopleFragment extends Fragment {
public FindPeopleFragment(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_find_people, container, false);
Button btn = (Button) rootView.findViewById(R.id.butto);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
FragementDemo fd = new FragementDemo();
android.support.v4.app.FragmentTransaction ft =
getFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fd); // content_frame is your FrameLayout container
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
});
return rootView;
}
}
And your next child activity will extend Fragment not Activity like this :
public class Friends extends SherlockFragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragementdemo, container, false);
// use button click code as used in FindPeopleFragment
return rootView;
}
}
Hope it works fine now for you!!