I have an activity that starts another activity.
Is it mandatory that I specify the parent activity in the Android Manifest?
Im asking this because there might be other activities that will start this one as well, so should I specify all of them?
android:parentActivityName="com.example.myfirstapp.MainActivity"
As per docs -> section android:parentActivityName:
The system reads this attribute to determine which activity should be started when the user presses the Up button in the action bar. The system can also use this information to synthesize a back stack of activities with TaskStackBuilder.
So you only need to specify that if you're going to use up-navigation (as opposed to navigation by back button) or TaskStackBuilder. In other cases, you don't need it.
For more information, see the up-navigation docs. (Archived from the original, which now redirects to the Jetpack Navigation docs on designing navigation graphs)
While it should be defined if upward navigation or backstack synthesis is desired, note that the attribute android:parentActivityName was introduced in API Level 16.
For prior releases, parent activity information is accessed from attributes defined inside of a <meta-data> tag that is declared inside of the child <activity> tag.
Example:
<activity
android:name=".DetailActivity"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity"/>
</activity>
Inside of the <meta-data> tag, set the android:name attribute to android.support.PARENT_ACTIVITY, and the android:value attribute to the parent activity class name (i.e. the same class name as that assigned to android:parentActivityName).
Unless API level is known, both the <meta-data> and inline specifications are recommended.
For more on specifying the parent activity, see: https://developer.android.com/training/implementing-navigation/ancestral.html#SpecifyParent
In addition, consider defining the android:launchMode attribute inside of your main <activity> tag to set the desired behavior of upward navigation: https://developer.android.com/guide/topics/manifest/activity-element.html#lmode
You don't necessarily need to define the parentActivity in the AndroidManifest.xml. You can use the below code for the back navigation enabled:
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
And implement this:
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == android.R.id.home) {
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
But if you define the parentActivity in the manifest, then the system reads this attribute to determine which activity should be started when the user presses the Up button in the action bar. i.e, it will create a new instance of the parentAcivity, means it will call the onCreate() of the parent activity.
You have to specify every Activity in the manifest which you call via Intent or Launchers, that the system can find it. So, mark one Activity as the Launcher that your App can get started and register every other Activity, which you call in your App.
If you have a BaseActivity like this:
public class BaseActivity extends Activity{}
public class MyActivity extends BaseActivity{}
than you only have to register MyActivity, because BaseActivity is not called by the system but you.
No its not necessary to specify parent activity in manifest like this
android:parentActivityName="com.example.myfirstapp.MainActivity"
for navigationUp you can also use setDisplayHomeAsUpEnabled(true); and onSupportNavigateUp() method Take a Look at this
Related
In my activity, I have:
<activity
android:name=".ChildActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.ParentActivity" />
</activity>
ChildActivity can be accessed via a standard launcher icon on the device.
My problem is when the user accesses ChildActivity via the launcher icon, then presses the Up button in the action bar, the app exits rather than going up to ParentActivity. This is because ParentActivity hasn't been instantiated.
Not sure if it's the best way, but I am trying to solve the problem by overriding onSupportNavigateUp(). However, I don't know how I can detect if the parent activity has been instantiated:
#Override
public boolean onSupportNavigateUp() {
boolean hasParentActivityBeenInstantiated = ???;
if (hasParentActivityBeenInstantiated) {
return super.onSupportNavigateUp();
}
else {
Intent upIntent = NavUtils.getParentActivityIntent(this);
startActivity(upIntent);
finish();
return true; // Up navigation completed successfully and this Activity was finished.
}
}
So how can I determine if the parent activity has been instantiated? More importantly, in this case, is overriding onSupportNavigateUp() the right way to navigate to the parent activity?
I would suggest not to guess if parent activity is instantiated or not, but use android:launchMode="singleTop" for parent activity. I think it is also fine to use onSupportNavigateUp unless you refactor your app to be single-activity with single navigation graph. Imo navigation framework leaves no choices for multi activity setup.
If for some fancy reason you need to explicitly know if it's up, you can use various techniques including static field initialization, flagging some field inside the application instances etc.
I did similar implementation (kotlin) and I was using onBackPressed for the purpose but it probably doesn't suite your situation (I was handling all the descendant fragments sys back press) however I would suggest using TaskStackBuilder if your depth of child/parent is bigger then one:
override fun onBackPressed() {
val upIntent: Intent? = NavUtils.getParentActivityIntent(this)
checkNotNull(upIntent) { "No parent activity intent" }
TaskStackBuilder.create(this)
.addNextIntentWithParentStack(upIntent)
.startActivities()
finish()
}
When I use an intent to move from parent activity to another, and then use action bar nav to go back to parent, the parent activity has lost all my changes and values (as a user) and is back to default xml display i have for it.
I have these in my Child activity OnCreate:
ActionBar actionBar = getSupportActionBar();
actionBar.setHomeButtonEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
And labeled my parent activity appropiately:
android:parentActivityName=".MainActivity"
What do I need to make it store or remember those changes when traveling between activities?
In the Manifest file, you should set android:launchMode like this:
<!-- ACTIVITY -->
<activity
android:name=".activities.MainActivity"
android:configChanges="orientation|screenSize"
android:launchMode="singleTask"
android:screenOrientation="portrait"/>
P.s: read Launch Mode on this link:
https://inthecheesefactory.com/blog/understand-android-activity-launchmode/en
There are couple of options to try -
1) start the new activity with startActivityForResult()
2) in the manifest file, set the android:launchMode="singleTop" of the parent activity
Hope it helps
You might be creating a new instance of your parent when you click the Navigation button. A simple approach is to just finish your activity so whatever activity in the backstack will simply be resumed.
Something like this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
I need to navigate from one page to its corresponding previous page(there are more than one previous page for current page in my app) . How can I implement it using Up Navigation / Back button.
Android documentation
Setup parent in Manifest file and then on Activity
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
or You can call finish() instead of
NavUtils.navigateUpFromSameTask(this)
You have to use either ActionBar or ToolBar.
Then simply add setDisplayHomeAsUpEnabled(true).
On activities it is by default getting back to previous using back button, but no up button. If you want up, put in Manifest:
android:parentActivityName=".MainActivity"
on Fragments:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.addToBackStack("Tag");
. . .
You can specify parent activities in the manifest
Beginning in Android 4.1 (API level 16), you can declare the logical parent of each activity by specifying the android:parentActivityName attribute in the element
If your app supports Android 4.0 and lower, include the Support Library with your app and add a element inside the . Then specify the parent activity as the value for android.support.PARENT_ACTIVITY, matching the android:parentActivityName attribute.
For example:
<application ... >
...
<!-- The main/home activity (it has no parent activity) -->
<activity
android:name="com.example.myfirstapp.MainActivity" ...>
...
</activity>
<!-- A child of the main activity -->
<activity
android:name="com.example.myfirstapp.DisplayMessageActivity"
android:label="#string/title_activity_display_message"
android:parentActivityName="com.example.myfirstapp.MainActivity" >
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.myfirstapp.MainActivity" />
</activity>
</application>
With the parent activity declared this way, you can use the NavUtils APIs to synthesize a new back stack by identifying which activity is the appropriate parent for each activity.
You can refer How to implement the Android ActionBar back button? for implement UpNavigation in your activity
I hope it helps.
In my app, each activity has the same menu in the action bar, which provides access to the parameters activity.
When I am in the parameters activity, I would like to get to my parent activity by clicking on the left-orriented arrow like in my other activities.
The unique parent of others activities is defined in manifest.xml.
But for the parameters it's impossible as it has multiple parents:
mother > child > parameters is possible
mother > parameters is also possible!
We can find this comportment in the gmail app:
main > parameters, in which you can get back to main
main > email > parameters, in which you can get back to the specific email you were looking at.
So my question is how to get this gmail comportment? Can we change dynamically the parent activity of parameters?
There are two ways in which you can accomplish this:
Use a TaskStackBuilder and specify the parent chain in the manifest using android:parentActivityName and the associated support-v4 meta-data tag as described in the corresponding Providing Up Navigation training. This is the recommended method as it obeys the hierarchical task stack.
Provide some extra into the launch intent and navigate up depending on that custom flag. Note that launching activities through this mechanism will not show the back animation of the current activity closing.
Comments mess up well indented answer so I anwser my question :
I finally ended up with a simple custom code,
because I had already visited a few times your link (http://developer.android.com/training/implementing-navigation/ancestral.html#NavigateUp) and it didnt helped me much.
Here's what I did :
(in the else of http://developer.android.com/training/implementing-navigation/ancestral.html#BuildBackStack)
// particular case
// if this activity is the Parameter/Help activity, just finish it
if(this.getClass().equals(ActivityParametre.class) || this.getClass().equals(ActivityAide.class)){
finish();
return true;
}
// general case
// otherwise, use pre defined code
else {
NavUtils.navigateUpTo(this, upIntent);
}
In the "System Back after cross navigation to lower hierarchy levels" section of the Navigation Drawer, they say:
If the user navigates to a lower hierarchy screen from the navigation
drawer and the screen has a direct parent, then the Back stack is
reset and Back points to the target screen’s parent. This Back
behavior is the same as when a user navigates into an app from a
notification.
I know the back stack can be reset by starting an activity with FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_NEW_TASK, but that does not seem to be usable here, as it would not create a back stack for Lower 1.1.1.
Any idea how to remove TopView2 from the stack and at the same time add the TopView1 -> Lower 1.1 back stack when starting Lower 1.1.1 ? I'm expecting a simple solution, considering this is mentioned in the Navigation Drawer document.
EDIT Synthesized version:
1)Declare the hierarchical navigation structure of your app in your manifest file.
2)The root activity of your app should perform a view switch between the TopViews in your app hierarchy.*
3) Activities lower in the hierarchy should perform 'Selective Up' navigation.
*Important: you should not add transactions to the back stack when the transaction is for horizontal navigation such as when switching tabs or navigation drawer top views.
Full description:
You should avoid the use of Intent Flags with the new navigation patters like Navigation Drawer for the next reasons:
Intent Flags are not really an API.
Some flags only work in exact combinations.
Many flags are not relevant for most 3rd party apps.
Overlap/conflict with activity launchMode.
Confusing documentation.
Implementation can become a process of trial and error.
Instead, opt for the new Navigation API:
Native Up navigation for Jelly Bean and above.
Based on hierarchical metadata specified for each <activity> in your manifest.
The support library provides equivalent functionality for earlier android versions via NavUtils.
TaskStackBuilder offers additional utilities for cross-task navigation.
So to answer your question the general idea is:
1) You need to declare the logical parent of each activity in your manifest file, using the android:parentActivityName attribute (and corresponding <meta-data> element) like:
<application ... >
...
<!-- The main/home activity (it has no parent activity) -->
<activity
android:name="com.example.myapp.RootDrawerActivity" ...>
...
</activity>
<!-- A child of the root activity -->
<activity
android:name="com.example.myapp.Lower11 "
android:label="#string/lower11"
android:parentActivityName="com.example.myapp.RootDrawerActivity" >
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.myapp.RootDrawerActivity" />
</activity>
<activity
android:name="com.example.myapp.Lower111 "
android:label="#string/lower111"
android:parentActivityName="com.example.myapp.Lower11" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.myapp.Lower11" />
</activity>
</application>
2) In your root Activity, drawer item selection should initiate a 'view switch' action by replacing the Activity's current fragment content.
A view switch follows the same basic policies as list or tab navigation in that a view switch does not create navigation history.
This pattern should only be used at the root activity of a task, leaving some form of Up navigation active for activities further down the navigation hierarchy (In your case Lower 1.1 & Lower 1.1.1). The important thing here is that you don't need to remove TopView2 from the stack but to perform a view switch as commented before passing the position of the view (or fragment id) as an extra.
In your root Activity do something like this:
#Override
protected void onDrawerItemSelected(int position) {
// Update the main content by replacing fragments
CategoryFragment fragment = new CategoryFragment();
Bundle args = new Bundle();
args.putInt(RootDrawerActivity.ARG_SORT, position);
fragment.setArguments(args);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment).commit();
// Update selected item and title, then close the drawer
setDrawerItemChecked(position, true);
setTitle(getResources().getStringArray(R.array.drawer_array)[position]);
closeDrawer();
}
3) Then lower in the hierarchy (i.e. Lower1.1) you should perform 'Selective Up' navigation, recreating the task stack in the process.
Selective Up allows a user to jump across an app's navigation hierarchy at will. The application should treat this as it treats Up navigation from a different task, replacing the current task stack (This is what you want!) using TaskStackBuilder or similar. This is the only form of navigation drawer that should be used outside of the root activity of a task.
#Override
protected void onDrawerItemSelected(int position) {
TaskStackBuilder.create(this)
.addParentStack(RootDrawerActivity.class)
.addNextIntent(new Intent(this, RootDrawerActivity.class)
.putExtra(RootDrawerActivity.ARG_SORT, position))
.startActivities();
}
Refs:
http://developer.android.com/training/implementing-navigation/ancestral.html
https://speakerdeck.com/jgilfelt/this-way-up-implementing-effective-navigation-on-android