I am using google's default navigation drawer activity. in the menu of the drawer, I added added menu items that when clicked open other activities (not as fragments). These activities have the MainActivity as parent, which has the drawer. The Activities have the back button in the toolbar. When this back button is pressed, the app just goes back to the mainactivity with a closed drawer. How can I have the drawer opened whenever the back button is pressed in the child activities.
I know this could be easily solved by having the other activities be fragments, but that is not what I am going for.
You can ovveride onBackPressed() inside the activity(s) whose parent is MainActivity. And pass a value using a key value pair and check the data inside onCreate of the MainActivity using bundle and then openDrawer inside MainActivity as follows
Inside you ChildActivity
#Override
public void onBackPressed() {
Intent intent = new Intent(ChildActivity.this, MainActivity.class);
intent.putExtra("openDrawer", true);
startActivity(intent);
super.onBackPressed();
}
And then inside onCreate of MainActivty.class
private boolean openDrawer = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
Bundle bundle = getIntent.getExtras();
if(bundle != null) {
openDrawer = bundle.getBoolean("openDrawer");
}
if (!openDrawer) {
// Do other stuff and don't open drawer
} else {
//Open drawer login goes here
}
}
Related
I have two Activities A and B.
Activity A has a Tablayout with some Tabs. When I navigate from A to B I use this:
Intent intent = new Intent(A, B.class);
A.startActivity(intent);
When I now navigate back from B to A I have a question:
1) When using Android's back button, the selected tab / scrolling position from A was remembered
2) When using an Intent or NavUtils.navigateUpFromSameTask(this); then the selected tab and scroll Position is NOT remembered but set to initial value
Can someone explain me what is going on here?
1) when navigation from activity A to B, the android system does not destroy activity A, but takes it to the back stack and adds B to the foreground. thats why when you press the back button or call onBackPressed() from the java code activity B is destroyed and A is set to the foreground. here is an example from the docs : Understand Tasks and Back stack
2) when using an intent/navigateUpFromSameTask activity A is recreated and set to the foreground and B is set to the background, it's like adding another activity A to the stack so it will be A,B,A but if you press the back btn then you will be back to B and then A.
if you want to keep the scroll position and other data in activity A you call the onBackPressed in B or use the onSaveInstanceState to save the data and use it in the onCreate .
here is an example of saved instance:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString("VariableName", variableData);
savedInstanceState.putString("VariableName", variableData);
savedInstanceState.putString("VariableName", variableData);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.penguin_main);
if(savedInstanceState!=null){
bookData = (String) savedInstanceState.getSerializable("VariableName");
bookData = (String) savedInstanceState.getSerializable("VariableName");
bookData = (String) savedInstanceState.getSerializable("VariableName");
}
}
You can set the current scroll position and tab position in activity A's on overriding onSaveInstance(Bundle savedInstanceState) method. When return to activity you can get onRestoreInstanceState(Bundle savedInstanceState) to restore it.
Hope it helps :)
Because NavUtils.navigateUpFromSameTask() just calls startActivity() and if android:launchMode="standard" the activity will be instantiated and created again and that is why can not remember the previous selected tab. To solve this issue you can override onNavigateUp() and inside that setCurrentItem(index) the index of tab you want to be displayed.
#Override
public boolean onNavigateUp() {
myViewPager.setCurrentItem(position, true);
return true;
}
Edit
You can use another solution to solve the problem by setting android:launchMode="singleTop" on activity but this solution may not applicable in all the application.
When you start an Activity, the first page will be opened! But when the back button is pressed, it navigates between the saved state of the activityTo simulate the back button pressed, you can try this:
#Override
public void onBackPressed() {
finish(); //your choice, thought not needed as super.onBackPressed(); is called if nothing is assigned here
}
or on toolbar back button clicked click:
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
I have an implementation of fragment as explained here. I have expanded the BaseFragment class to handle navigation icon onClickListener. The code for that looks like this,
private void onBackButtonPressed(int tag)
{
switch (tag)
{
case Global.DISPLAY_STORE:
{
setTitle("Loyalty Cards",Color.BLACK);
setToolBar(getResources().getColor(R.color.white), Global.ADD_CARD,R.drawable.add_round_btn);
break;
}
case Global.ADD_CARD:
{
setTitle("Wallet", Color.WHITE);
setToolBar(getResources().getColor(R.color.colorPrimary), Global.DISPLAY_STORE,R.drawable.icon_shopping);
getFragmentManager().popBackStack();
break;
}
case Global.CARD_DETAILS:
{
setTitle("Loyalty Cards",Color.BLACK);
setToolBar(getResources().getColor(R.color.white), Global.ADD_CARD,R.drawable.add_round_btn);
getFragmentManager().popBackStack();
break;
}
}
}
I am using this block of code to change the ToolBar icons and colors when back button is pressed.This code resides in BaseFragment.
Here is how I implement the code to handle back press,
I have my fragment extending the BaseFragment
public class CardDetailsFragment extends BaseFragment
Now inside the BaseFragment onCreate I have this code,
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainActivity = (MainActivity) getActivity();
ImageButton righBarButton = (ImageButton) mainActivity.getToolbar().findViewById(R.id.btn_ToolBarRightBtn);
righBarButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onRighBarButtonClicked(Integer.parseInt(v.getTag().toString()));
}
});
mainActivity.getToolbar().setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackButtonPressed(BACK_BUTTON_TAG);
}
});
getFragmentManager().addOnBackStackChangedListener(this);
shouldDisplayHomeUp();
}
By this every fragments back button press and the right bar button item click in toolbar are handled.
Consider the scenario I have three fragments A , B and C.
From Fragment A I open Fragment B and Then Fragment C. Now From fragment C I click the back button to reach fragment B. The back button event is handled by above code and it works fine.
Now from Fragment B, I click the back button to reach Fragment A. But when I click back button I am getting exception
java.lang.IllegalStateException: Fragment CardDetailsFragment{d8b35b5} not attached to Activity
at android.support.v4.app.Fragment.getResources(Fragment.java:636)
here the CardDetailsFragment is the FragmentC, but I am clicking the
back button from Fragment B
The first time the user presses the back button, Fragment C is no longer necessary and thus it is detached from the activity. The problem lies in the fact that even though Fragment C is detached, it is still registered as a listener for back stack change events.
The second time the user presses the back button, your onBackStackPressed() method is called in Fragment C. When getResources() is executed, there is no activity attachment so getResources() fails.
Something like this in your fragment should fix it:
#Override
public void onDestroy() {
getFragmentManager().removeOnBackStackChangedListener(this);
super.onDestroy();
}
I have 2 Activity(s). Inside 1st Activity there is initially one Fragment
MainActivity.java
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.myactivity);
if(savedInstanceState == null) {
getFragmentManager().beginTransaction().replace(R.id.fragmentContainer, MainFragment.newInstance().commit();
}
}
}
then clicking on a button replaces it with another Fragment.
#Override
public void onClick(View arg0) {
DetailFragment detail = (DetailFragment)getFragmentManager().findFragmentById(R.id.detail);
getFragmentManager().beginTransaction().replace(R.id.detail, detail, "detail").commit();
}
On 2nd Fragment there is another button, clicking on it opens a New Activity.
Intent popUp = new Intent(MainActivity.this, PopUp.class);
popUp.putExtra("CarID", carID);
startActivity(popUp);
From PopUp Activity, pressing device back will go back to MainActivity.
Now the challenge is for the Application's business logic I need to update the ActionBar's title of previous MainActivity when user goes back.
For this I'm listening for onResume() on both MainFragment and DetailFragment. Also when user goes back from DetailFragment to MainFragment I update the ActionBar title with different text.
So I need to know when exactly user goes back from:
1) PopUp Activity > Detail Fragment
2) Detail Fragment > Main Fragment
Currently onResume() is fired on both MainFragment and DetailFragment when PopUpActivity is closed. On MainFragment I can't exactly find out whether onResume() is called for 1st or 2nd case.
What is the best practice to fire onResume() on DetailFragment only when user goes back from PopUpActivity > DetailFragment. In other words, how do I detect from DetailFragment that PopUpActivity is closed without firing onResume() on MainFragment.
I wouldn't mess with onResume() for something like this.
I would suggest doing the following:
Create a Stack<String> for titles.
Implement FragmentManager.OnBackStackChangedListener in your MainActivity.
In your onBackStackChanged() implementation, check if the back stack has been pushed or popped using FragmentManager.getBackStackEntryCount().
If the back stack has been pushed, push the newly-displayed fragment's title to your title stack.
If the back stack has been popped, pop a title and set the title bar with the title at the new top of stack.
If you set a title from a fragment that isn't added to the back stack, pop a title from the title stack and push the newly-displayed fragment's title, i.e. replace the title at the top of the stack.
Invoke your PopupActivity with startActivityForResult() instead of startActivity().
Override onActivityResult() in your MainActivity so that when PopupActivity returns, you set the title bar with the title at the top of stack.
Don't forget to persist your title stack in onSaveInstanceState() in your MainActivity and restore it in onCreate().
That might seem like a lot of work just for maintaining titles, but you will drive yourself crazy trying to do this with onResume.
try it:
#Override
public void onResume() {
super.onResume();
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
// handle back button
return true;
}
return false;
}
});
}
I have 2 viewpagers: swipeViewPager and nonSwipeViewPager in MainActivity
In swipeableViewPager, I have fragments: homeFragmentFirst and homeFragmentSecond
In nonSwipeableViewPager, I have fragments: AppleFragment , MangoFragment, GrapesFragment and CherryFragment
First I want swipeableViewPager to be viewed in MainActivity. So I have set setVisibility of nonSwipeableViewPager as GONE.
After selecting an item from the drawer, I setVisibility of swipeableViewPager as GONE and of nonSwipeableViewPager as Visible.
By this, I open AppleFragment
Situation:
Suppose, I selected Grapes from drawer, GrapesFragment opens.
I do my some stuff there. And then when I press back button, the app closes i.e. the MainActivity closes.
What I want is when back button is pressed, I want to again bring back homeFragmentFirst from swipeableViewPager.
I have tried below code in GrapesFragment
#Override
public void onBackPressed() {
super.onBackPressed();
// Do some operations here
MainActivity mainActivity = new MainActivity();
mainActivity.swipeHomeViewPager.setVisibility(View.VISIBLE);
mainActivity.nonSwipeHomeViewPager.setVisibility(View.GONE);
}
I solved it myself. I added following in MainActivity:
#Override
public void onBackPressed() {
if (nonSwipeHomeViewPager.getVisibility() == View.VISIBLE) {
nonSwipeHomeViewPager.setVisibility(View.GONE);
swipeHomeViewPager.setVisibility(View.VISIBLE);
swipeHomeViewPager.setCurrentItem(0,true);
} else if (swipeHomeViewPager.getVisibility() == View.VISIBLE){
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
}
You can implement backstack for the fragments (while adding / replacing fragment) add it to backstack. the back press will automatically take you to previous fragment.
otherwise you need to override OnBackPressed method to handle with your own logic.
I've got a Main Activity which is a search interface, when the user clicks a result in the list, the result details are displayed in a Fragment. The Main Activity has an Action Bar, but in the details Fragment, the Action Bar is hidden. To hide the Action Bar in the Fragment, I'm calling a method in the Main Activity from the Fragment Activity like this: ((SearchInterface)getActivity()).hideABar();. Then when the user clicks the back button, they go back to the search interface and the Action Bar reappears. Doing that is a bit more complex than simply calling a method. I set up an Interface in the Main Activity and override the method in the Fragment like this:
Main Activity:
public interface Callback {
public void onBackPressedCallback();
}
#Override
public void onBackPressed() {
super.onBackPressed();
if(fragBackPressed != null)
fragBackPressed.onBackPressedCallback();
checkActionBarState();
}
...
public void checkActionBarState(){
bar_AB = getSupportActionBar();
boolean barVisible = bar_AB.isShowing();
if(barVisible){
Toast.makeText(getApplicationContext(),"ActionBar WAS Visible",Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getApplicationContext(),"ActionBar WAS NOT Visible",Toast.LENGTH_LONG).show();
bar_AB.show();
}
}
Fragment:
#Override
public void onBackPressedCallback() {
Log.d("SSIVideoFrag", "checking action bar state");
}
So now, when the user presses the Back button while in the Details Fragment, they go back to Main Activity and the Action Bar reappears. Now I'd like to add a button in the Details Fragment that does what clicking the Back button does, but I can't figure out how to do it. I don't know how to override the onBackPressedCallback() method from within the onClick of a Button:
back_BTN.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
//--- what to do here?
}
});
simple:
getFragmentManager().popBackStack();
https://developer.android.com/reference/android/app/FragmentManager.html#popBackStack()
ps.: that's not an actual back press, your onBackPressed will not be called. But the fragment will be removed, just like in a back press.