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();
}
});
Related
I have an Activity (A) that contains a ViewPager which calls a Fragment to present information to the user (this Activity A is called from an Activity B). My Fragment contains a VideoView which plays an MP4 with GIF behavior. My problem is when I want to return to Activity B, since when doing a Finish () in the onBackpressed in Activity A, for a few milliseconds the videoView looks over the contents of Activity B.
UPDATE
I discovered that the problem is due to the ViewPage.
It happens that when I'm in position 0, calling the onBackPressed method works everything ok. But when the onBackPressed method is called from another position, closing the Activity momentarily shows the VideoView of the previous position.
#Override
public void onBackPressed() {
if (mViewPager.getCurrentItem() != 0) {
//I don't know what to do here
}
super.onBackPressed();
}
Please finish your call when you Back pressed.
public void onBackPressed() {
if (/--logic--/) {
finish();
}
}
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
}
}
I'm having some problems with navigation and the up button of the activity. I have two tabs implemented with Viewpager in one activity and then another activity which is loaded from the previous one. When the user clicks the phone's back button or the activity's up button, I want to go back to the previously selected tab and fragment of the first activity.
So far I've been able to do it for the back button, with onSaveInstanceState and the following code:
#Override
protected void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putInt("currentPage", mViewPager.getCurrentItem());
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
int page = savedInstanceState.getInt("currentPage", 0);
mViewPager.setCurrentItem(page);
getSupportActionBar().setSelectedNavigationItem(page);
}
}
Why is this not working for the up button? What do I have to do?
Any help is appreciated and sorry if this is an issue easy to solve, but I'm rather new to the Android programming.
I finally found the solution at Returning from an activity using navigateUpFromSameTask(). savedInstanceState was null when the activity was recreated. To avoid so, the launch mode of the activity has to be declared as singleTop in the Android manifest.
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 three activites, lets call them A, B, and C.
I initially have activity A passing data with intent and calling activity B to open, displaying the data passed from activity A.
Now the issue is when I open activity C from activity B, and use the up navigation that I set up by setting activity B as the parent of Activity C in manifest, none of the data is displayed from Activity A in Activity B. If i simply make a button and call finish(); on the button instead, and not use the up navigation, the activity still contains all data from activity A just how I want it in Activity B.
I'm assuming this has to do with the lifecycle of using up navigation? I even tried using the intent from activity B to C by passing data, and then onResult have it return back to activity B, but it seems the onActivityResult is never called when up navigation is clicked. Any ideas? Maybe I can override this up navigation to just call finish(), like my button does, and nothing more?
Assuming you already have the parent activities defined at the Manifest, make sure you override the following methods:
#Override
public void onCreate(Bundle savedInstanceState) {
// You code here
getActionBar().setDisplayHomeAsUpEnabled(true);
// or getSupportActionBar().setDisplayHomeAsUpEnabled(true) if using support actionbar, i.e., for targets < 3.0;
}
Now you will be able to catch the action of the "Up" button with the Id android.R.id.home.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}