Android Activity is not displayed after previously shown with ActivityFlags NewTask + ClearTask - android

I am catering for two specific scenarios
Ensure user is forced to Login if the app was running when device is
locked and then then unlock it
When the user logs out unwind the back stack and take them to the login page
As I need to customise with how Views are loaded I have implemented a Custom View Presenter (MvxAndroidViewPresenter) see SplitViewPresenter presentation
For scenario 2 I pass some PresentationValues in the Request to signal that I want to do something different when showing the LoginView
if (request.PresentationValues != null && request.PresentationValues.ContainsKey(MakeViewTopHint.HintName))
{
intent.AddFlags(ActivityFlags.NewTask);
intent.AddFlags(ActivityFlags.ClearTask);
}
This causes the the stack do be unwound and the LoginView is shown. Great.
For scenario 1 I use a BroadcastReceiver to catch the Intent, ActionScreenOff. Then I try to show the same Activity that was previously shown with a NewTask and ClearTask.
Scenario 1 works fine if I remove the NewTask and ClearTask flags used for Scenario 2 but I need them to clear the back stack down.
Does anyone know why the use of NewTask and ClearTask would be preventing the Activity from being shown subsequently

The problem was MVVMCross's MvxAndroidViewsContainer.AdjustIntentForPresentation. It sets the NewTask ActivityFlag on the Intent that is used for Scenario 1.
In fairness there is probably a good reason for this but when NewTask is used to start an Activity after previously starting that Activity with NewTask and ClearTask it will not resolve and the Activity is not displayed.
Thanks to MVVMCross' almost limitless configurability I am able to create a custom AndroidViewsContainer. When Scenario 1 is being played out I ensure that the NewTask flag is not used and everything works.
The issue of ActivityFlags.NewTask preventing the Activity from being resolved is not an MVVM cross or Xamarin thing as I can now repro, what I consider to be odd behavior, in vanilla Android.
I now have a working solution to both scenarios
Force user to Login after a device Lock/Unlock
Unwind the back stack and send user to Login when they log out

Related

How to show disclaimer once per run of app

This is harder than it sounds, which is why I'm asking for solutions.
Basically I only want the disclaimer Toast shown once per run of the app.
The app is in two parts, all are Activities.
It's shown when it starts in the first part, but you can hit a menu button
taking you to the second part of the app, which has another menu button
to take you back to the first.
The problem is that whatever initial settings you try to make in the first
part, when it starts up, are run again when returning from the second
part of the app, so it'll show again.
My last idea was that in the first part's onDestroy(), when the app exits, but is not the case in this situation, you set a boolean in settings,
to reset that the disclaimer can be shown, but apparently, onDestroy() is called on the first part before it goes to the second part.
Or, if you can get it to not show the first run, but behave properly
every time after that, that would be okay.
And there doesn't seem to be any method to be called when the app truly
is "killed", if there was that would be the way to do it, you could reset it there. Or if there was a method that was only called when the app first started..
Thanks!
You just need a boolean flag. Say we call it disclaimerShown. In onCreate() of Activity A, we check both the Intent Bundle and the savedInstanceState Bundle for this flag.
You can add the boolean to a Bundle when launching the Intent to start Activity A from Activity B.
If the user is in Activity B and presses the Back button to return to Activity A, you can override onBackPressed() in Activity B and include your flag there as well (though you'll have to catch this flag on onActivityResult() in Activity A).
If system initiated process death occurs in Activity A, the system will call onSaveInstanceState(Bundle bundle). So you add your flag to this bundle as well.
And if system initiated process death occurs in Activity B, you have nothing to worry.
And that handles all possible cases.
An elegant solution for this problem would be the ProcessLifecycleOwner.
This class provides callbacks to the lifecycle of your whole app (not individual activities) and you could use the Lifecycle.Event.ON_CREATE callback to show your toast once. Look at this stackoverflow question for a usage example of the ProcessLifecycleOwner.
It turns out that I already had an Activity that started before
my "Activity A", and I moved my disclaimer Toast there
and it works fine. You can't beat that simplicity lol.
Thanks for your answers!

How can you start a different activity in android according to the intent's data

I am making an application that will in fact contain two activities.
One will allow the user to log in and if done successfully will launch a web browser (MenuActivity).
The other takes a picture and uploads it to a server (PhotoActivity).
That web browser will have a link that when pressed will load my application in picture taking mode.
The flow is usually something like this:
MenuActivity->web browser->PictureActivity and then the last two steps repeat.
I have done this so far by setting my launcher activity as the MenuActivity and then putting using this code in the OnCreate override:
Intent mine = getIntent();
if (mine.getData() != null && !mine.getData().getPathSegments().isEmpty()) {
//retrieve the data here that I need
Intent i = new Intent(this, typeof(PhotoActivity));
i.PutExtra(//add here the data I received);
StartActivityForResult(i, START_PHOTO_INTENT);
}
after that I override OnActivityResult and send finish() if the requestCode is START_PHOTO_INTENT
This works correctly
my problem is that when I start the PhotoActivity from the web browser, if the user (while this is open) opens the application, then the MenuActivity shows (which it should) but when the user pressed back on it, it goes back to the PhotoActivity instead of exiting.
Is there a way to change this behaviour so that , even if the PhotoActivity is open, if the application is started manually, the PhotoActivity will not remain on the backstack ?
Thanks in advance for any help you can provide
Edit:
After reading the linked article at the solution and the answers to this question I came to the conclusion that in order to do what I want I had to set LaunchMode as singleTask in androidmanifest, and override MenuActivity's OnStop and send finish() after it was executed (if I didn't and the activity was in the backstack then it wouldn't be fired with the intent data when launched from a web page)
thanks for the help all of you
Look at the Handling affinities chapter in Tasks and Back Stack documentation. It is described how to handle this.
please do
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
This will start a new task for your application

Extras based REORDER_TO_FRONT

In an app I have very reused Activity, that shows a list of stuff happening on a specific day. The day is specified using Intent Extras.
My problem is, that if the user starts at day=1, then chooses day=2 and then day=1, from the menu, then I would like the back button to go to day=2 and then home. That is, I want to do REORDER_TO_FRONT, but not just based on the name of the activity, but also its extras.
There doesn't seam to be any intent flags suitable for this purpose. I've considered implementing my own 'sub activity stack' using onNewIntent, but it probably wouldn't work very well.
Have you tackled similar problems in your apps? Is there perhaps a way to programmatically access the activity stack, and choose which one is suitable to return to?
Manage your own Activity stack! If I'm not mistaken, you use the same Activity to display each day. Make it single top (FLAG_ACTIVITY_SINGLE_TOP). In the launching intent, pass on the current stack, in your example "121".
Respond to the back button event by launching your Activity with a smaller stack: "12" - or if stack is already "", then just let the Activity handle Back event. Then as you mentioned, use the onNewIntent function to update your Activity.

How to return to the same activity instance after resuming it?

The problem is somewhat odd and after having trying to figure it out for about a day now, I am posting it here.
I have an application where an activity A(main activity) launches other activities(B,C or D).
The issue here happens when activity A has started Activity B and 'home' button is pressed.
Case 1 - When I test my application in debug mode on my device (HTC Desire) after pressing the 'home' button, I again click the application icon, it returns to the same activity (activity B), which is what is should do. No issues here.
Case 2 - When I export the signed package, and then install the application on the same device, then if I click the application icon after pressing the 'home' button, then a new instance of activity A (main activity) is launched ON TOP of activity B. I got to know this because when I press 'back' from that activity, it returns to activity B and pressing 'back' again shown activity A.
The behavior ceases to exist if the application is quit in the same order it was started, that is, if I press 'back' from activity B, then 'back' from activity A (exit).
After this everything runs fine.
I have tested it many times with different settings but I can't seem to figure out why the behavior is like this.
Any help is appreciated.
I think giving Activity A the 'single top' flag in your manifest should fix this.
Regarding Case 1:
When launching your intent from Activity A to start Activity B, add the flag FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
This will ensure that when you go home and launch the the app again, Activity A will be shown.
Regarding Case 2:
I'm not exactly sure how this would occur. It seems like it thinks you have two versions of the app, the signed one and the unsigned one but keeps them both in the same task stack. You may want to consider using singleTask or singleInstance for your Activity if you only want one instance. See the doc on tasks and back stack for more details.
I would agree with Noel regarding the likely cause of Case 2. Without task reparenting or it being set to a launchmode preventing multiple instances of an activity, there is a chance that launching it from Home isn't deemed the same stack as launching it from Eclipse (assuming this to be the case).
In my talent calculator app I have the whole application set allowTaskReparenting=true to ensure nothing is left in other stacks (primarily email as it can email launch urls). I then have my main activity set to launchMode="singleTask" as I only ever want one instance of this to exist no matter what launches it or with whatever intent.
My only other activity is for loading and saving and that has noHistory="true" to make sure it is removed and never returned to. That basically means it only exists while you're in it, and can never return to it.
clearTaskOnLaunch="true" will also ensure only the main Activity remains in the stack when it's launched from Home, but this isn't always the case if you have other ways to get into your activity. If it's only ever launched from Home then set this.
Hope that all helps.
Do you start you application manually or using Eclipse or another IDE? When starting from Intellij IDEA I had exactly the same problems. Then I stopped and ran it manually and behaviour was as expected.

Android Run application from last Activity

I have an application with several Activities.
My A Activity has the Manifest Intent filter parameters: action.MAIN
and category.LAUNCHER. after its being loaded I call Activity B and
finish() A since I don't use it anymore.
After I run my application, go from Activity A to B and press the Home
button, when I relaunch it from the applications menu or from the
Market app for ex.(not by a long press on the Home button), starts
from the A Activity and do not save its last Activity B.
I definitely know that this is possible to relaunch an application
from its last Activity (some applications from the Market do support
it) and I think that this can be determined by the Manifest parameters
but I don't know which one.
does anyone know how to implement it so my application can relaunch
from its last Activity B?
Thanks
ayanir
Though I know this is an old question, I was struggling with this very issue and couldn't find an answer on SO. So, here is my (very newbie) answer:
No, I do not think it's possible to do this by messing with the manifest - you can only launch one fixed activity per app from the home screen. What you can do, though, is launch whatever activity you want from that starting point, and Android can do it quickly enough that you never see the first one.
Though this feels very much like a hack, I implemented this routing in the starting activity's onResume() method, and used sharedPreferences to keep track of which activity to launch:
final Class<? extends Activity> activityClass;
SharedPreferences prefs = getSharedPreferences("sharedPrefs", MODE_PRIVATE);
int activityID = prefs.getInt("whichActivity", -1);
if (activityID == Constants.ACTIVITY_ID_MAINSCREEN) {
activityClass = MainScreen.class;
} else {
activityClass = null; return;
}
Intent newActivity = new Intent(this, activityClass);
this.startActivity(newActivity);
There have been a number of very similar questions lately. It's a good idea to search the site first to ensure that duplicate questions don't get asked.
For example, the question linked below says that this behaviour was happening because the developer was starting their application using the Eclipse debugger. Another person was having this problem because they were launching the application directly from Eclipse, rather than starting cleanly by manually pressing the launcher icon.
Android: keep task's activity stack after restart from HOME
so there are a few things to consider when developing Apps in Android. And one of the big things is the Application Lifecyle, if you haven't yet then I would suggest this video. What happens is that an application can be killed and reset at any point in time and you need to save the state of your application so that you can restore it at any time. If you open your App from the Launcher you will always go into the Activity that starts the app, if you want to skip to the next Activity you need to store that information and then jump to the Activity in your code.
Also have a look at this documentation about SavingPersistentState

Categories

Resources