I'm creating an app for a project. The thing is that I'm using BottomNavigationView to navigate through activites. However, there is an issue here, when I press the "Back Button", the app goes through every single page I've surfed even though I've been to a same tab multiple times.
What I want to reach is something similar to what Instagram has implemented: Going through a same tab just once despite having navigated through it previously.
Watch the gif to see what I mean. https://gyazo.com/a7f536dbe1b204923ea790db50e8a88e
I execute this code all the times I touch an item from BottomNavigationView.
case R.id.bnHome:
Intent intentHome = new Intent(context,HomeActivity.class);
context.startActivity(intentHome);
callingActivity.overridePendingTransition(R.anim.fade_in,R.anim.fade_out);
break;
The current situation: when I start to close: Search -> Profile -> Search -> Profile -> Home -> exit
What I'm expecting: when I start to close: Search -> Profile -> Home -> exit
This behavior could be reach with Fragments. Fragment it is like View but with own lifecycle similarly to Activity, they was created for reuse and decoupling UI. Here is an example how to build exactly what you need.
Firstly you need to use Fragment for more readable and maintainable navigation structure.
Secondly ,
Make your activity to single task
<activity
android:name=".MyActivity"
android:launchMode="singleTask" >
</activity>
Add finish() after your startActivity calls expect from Home.
case R.id.bnHome:
Intent intentHome = new Intent(context,HomeActivity.class);
context.startActivity(intentHome);
callingActivity.overridePendingTransition(R.anim.fade_in,R.anim.fade_out);
finish();
break;
It can be work but if you choose to use fragment you do not need to initialize bottom bar or common other views or actions for every page.
Related
I have 2 Activities in my Android application - Activity A and Activity B.
When the user presses a button on Activity A, he is navigated to Activity B.
I want Activity A to close after going to the next activity and is completely removed from the activity stack.
I tried adding intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); , but this not work as Activity A was still accessible after pressing the back button.
I added finishAffinity(); , this worked, but while transitioning, the previous activity in the activity stacks gets visible and then it goes to Activity B.
Video
(here the application drawer is shown, and then it goes to Activity B) -
Code -
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this);
Intent i = new Intent(MainActivity.this, MainActivity2.class);
startActivity(i, options.toBundle());
finishAffinity();
Any fix so that the previous activity is not visible and activity is also closed ?
EDIT : I tried finish(), finishAfterTransition() and supportFinishAfterTransition() instead of finishAffinity() but still the previous screen is visible.
So I guess there's an issue with finishAfterTransition()
I solved it by adding android:noHistory="true" attribute to the activity (which has to be removed from the stack) in the manifest file solves the issue.
There is no need to use finish() in the java code after this change.
Method 2 -
Refer #Pratyay ' s answer for a way around.
you have to use finish but like this:
startActivity(Your Activity here)
then Finish()
if you do reverse you can see black screen for a short time do this way
#Override
public void onBackPressed() {
finishAffinity();
}
Use this function in Activity B, this will exit app on pressing back button. And don't use any finish(); or finishAffinity(); in Activity A. This will give a smooth transition
I understand how to navigate between fragments using Jetpack's Navigation Component, but I haven't been able to find is how to navigate from one child fragment to another child fragment.
The following is what I've done so far:
https://pastebin.com/dNQ0Ep4S the code example is pretty big so sum it up, I'm trying to do is" A>B and Ba>Bb". Ba is a fragment inside of fragment B. I'm not sure how to set up the nav graph for something like that
The navigation works until the home fragment. The bot nav just doesn't seem to work. It always displays the pending layout. Another thing I tried was setting the nav graph of the home to the same one used for the login and adding the pending and history fragments to the nav file without any actions. But the home loads the login, the tabs work, but they're replacing the home fragment instead of being placed in the home nav host.
Update
I managed to find the problem, but I'm stuck trying to find a solution.
So B seems to be getting the navhost for A when I setup the botnavview to the navcontroller. So calling NavController navController = NavHostFragment.findNavController(this); from B returns the navhost of A. I'm at a lost here. If I do this NavController navController2 = Navigation.findNavController(currentActivity, R.id.homeNavHostFragmentContainer); (homeNavHostFragmentContainer being the navhostfor B) still returns the navhost for A. For some reason, I can't get a reference to B's navhost.
Usually we use: NavigationUI with jetpack, i recommend this, https://developer.android.com/guide/navigation with nav_graph.xml with NavigationDirections such as:
val direction = FirstFragmentDirections.actionSecondFragment()
Navigation.findNavController(requireView()).navigate(direction)
Or you can use non-jetpack way, i do not recommend, but depending on your UI you may need it:
fun displayChildFragment(frameId: Int, fragment: Fragment) {
requireActivity().supportFragmentManager?.let {
val transaction = it.beginTransaction()
//transaction.setTransition(TRANSIT_FRAGMENT_OPEN)
transaction.replace(frameId, fragment).commit()
}
}
My problem was that I misunderstood how NavHostFragment.findNavController() functions. Fragment B is not a navhost is just a regular Fragment. The navhost for B is a child of B. The argument for findNavController() has to be a NavHostFragment not a regular Fragment. So by passing, this (being B), it wasn't getting a NavFragment, just a regular Fragment. I thought the method would have extracted the navhost from whatever fragment was passed. Guess the documentation caused a bit of confusion. To get the correct navhost, I had to get the navhost from the fragment manager like so getChildFragmentManager().findFragmentById(navHostResId) (in my case, navHostResId was the id of the fragment container in B). Then everything worked beautifully.
Where does one actually place the code to launch the ParseLoginUI activity?
ParseLoginBuilder builder = new ParseLoginBuilder(MainActivity.this);
startActivityForResult(builder.build(), 0);
Is it in the ParseLoginDispatchActivity? This was not made very clear at all within any of the official documentation:
https://github.com/ParsePlatform/ParseUI-Android
https://www.parse.com/docs/android/guide#user-interface
I'm importing ParseLoginUI into my existing app. What do I once I've installed everything, updated my manifests, my build.gradle and now want to actually launch the Login activity once my app launches?
Do I put something in my manifest to indicate that the ParseLoginActivity should launch first? That doesn't seem to work as an Activity from my main application is required to launch as the initial intent. I'm a little lost here... Any thoughts?
Well I did find one solution, albeit a trivial one:
Intent loginIntent = new Intent(MainActivity.this, ParseLoginActivity.class); startActivity(loginIntent);
I launched the above Intent with an options menu item, but you could do it with a button or whatever else suits your needs.
If you're importing ParseLoginUI into an existing app, it appears you can just launch ParseLoginActivity with a simple Intent. I wish they mentioned this on their integration tutorial. Seems like the most straightforward way to get it running.
This solution definitely launches the Activity you want, but it doesn't check for whether the user is logged in or not and hence doesn't redirect you to the appropriate pages in your log-in flow (which I believe has more to do with your Manifest). It does, however, allow you to successfully register a user and log in with Parse, which is a great start.
A better solution would be to add the following to the onCreate method in the Activity that launches when your app launches. So if when your app launches you land on FirstActivity, the following will check to see if you are logged in. If you are not, you will be sent the login screen, and if you are logged in you will be sent to the second Activity, which is presumably where your users will want to be when they open your app.
ParseUser currentUser = ParseUser.getCurrentUser();
if (currentUser != null) {
Intent launchMainActivity = new Intent(this, SecondActivity.class);
startActivity(launchMainActivity );
} else {
ParseLoginBuilder builder = new ParseLoginBuilder(FirstActivity.this);
startActivityForResult(builder.build(), 0);
}
My Android app defines an activity with an intent filter of android.intent.action.CREATE_SHORTCUT, which lets me show up in the list of shortcuts that the user can add to their home page, when they select "Add Shortcut" from the menu or long-click the home page.
In this activity I have the following code (actually happens in a click event after they pick which shortcut to add):
Intent shortcutIntent = new Intent(this,MyActivity.class);
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ShortcutIconResource iconResource = Intent.ShortcutIconResource.fromContext(this, R.drawable.myicon);
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "MyAppName");
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource);
setResult(RESULT_OK, intent);
finish();
The shortcut works as I would expect, until I reboot the device. I'm actually testing on the emulator, not real device. The shortcut is still there after a reboot, so I know I didn't wipe user data or anything like that, but it acts like it no longer has the FLAG_ACTIVITY_NEW_TASK setting when clicked.
Example steps to recreate (assume my app is an email inbox for clarity):
Create the shortcut
Launch my inbox activity from my main menu acitvity, which uses the NEW_TASK flag.
From the inbox activity, click a message to open the view message activity.
Press HOME key
Click the shortcut -- at this point it brings the entire "task stack" back to the front, with the view message activity on top of the stack, clicking back goes back to the inbox activity, as I would expect
Reboot the device
Repeat steps 2 through 5.. now when I click the shortcut, instead of bringing the view message activity to the front, it brings the task to the front, but then adds a new inbox activity on top of the stack. So pressing BACK once goes back to the view message activity, and back again to the inbox activity.
I also tried setting different properties such as singleTask for my inbox activity in the app manifest, but haven't had any luck. Is this a known issue that flags are not saved with shortcuts?
I think I'll try adding a new stub activity that does nothing but launches the real activity with the NEW_TASK flag and then exits, and have my shortcuts point to that instead. However, seems like a lot of overhead, so hopefully someone has a better answer.
OK,I'm new at this forum, so don't blame me for putting this in the wrong tags,not putting something in,eg.
I want to learn how to create a shortcut(I did that by Googling) and link it to an activity (In this case, com.android.mms.ui.ComposeMessageActivity)
I tried doing it, but it only showed me a toast saying "Application not installed" and I'm pretty sure it is.
It would be better if you can display a "complete action with another application" dialog.
If I assumed your question correctly, you mean a button or something within an activity that leads to another activity, that being -- "com.android.mms.ui.ComposeMessageActivity"
if your activity that you want to link to is in another application-- then
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.mine", "com.android.mms.ui.ComposeMessageActivity"));
startActivity(intent);
if it is within the same application, then
Intent intent = new Intent(this, ComposeMessageActivity.class);
startActivity(intent);
//optional add this to your manifest to finish the current loading activity so
//as to not keep it in the activity stack
//<activity android:name="yourActivity" android:noHistory="true" ... />
EDIT If you mean a shortcut on a homescreen, then I would create a tiny application that only has one activity which uses the above method to link to a different application. Then I would drag that application to the home screen, and boom. If there's a better way, then please feel free to correct me