Android Activity from Notification - FragmentManager backstack is zero - android

I searched around but couldn't find an answer.
My app is based on fragments, and MainActivity is the entry point. When the user clicks on a notification, I trigger the desired behaviour with a PendingIntent that contains specific flags as to what fragment needs to be invoked.
My problem occurs when the fragment I need is already being displayed. When the MainActivity is entered through the PendingIntent, the fragmentManager.getBackStackEntryCount() will return zero. I guess that this happens because the activity is a different instance than what I already had running. Then the same fragment is invoked again and this messes up my UI (and potentially crash because the Otto bus had already been registered).
My question is: what is the best way to detect the state of the running app (i.e. which fragment is being displayed) when the activity is triggered from a notification? Thanks.

I guess you could do that with the FragmentManager class.
You have several interesting methods. For example, findFragmentByTag(String tag) enables you to know if a Fragment with a particular TAG exists.
Also, are you sure you are not recreating a new Activity (on top of the current one ) ?

Thanks to #Gordak suggestion, I was able to figure out my problem. What I needed was a combination of flags in my (pending)Intent:
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP|Intent.FLAG_ACTIVITY_CLEAR_TOP);
This way, if the invoked activity is on top, it won't be destroyed (thus keeping the FragmentManager's backstack) but the method onNewIntent(Intent intent) will be triggered, letting you react to it. This is described in the documentation for
FLAG_ACTIVITY_CLEAR_TOP.

Related

I have a trouble in Fragment life cycle and need a resolution to come out of it

I have done ample research on this, and there is not one clear solution on the problem.
In the life-cycle, particularly in the Fragment life-cycle, following Exception comes any moment after onPause().
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
My logic says, that to continue with the current fragment, after it reaches this state, I have to restart the activity and again point back to the intended fragment using Intent.
I want to be clear on what is happening and what should be real solution to deal with it.
I need to know the pros and cons of this mechanism; its importance in Fragment or Activity life-cycle.
Also, if I am changing the Windows Feature in onCreate to not to go to sleep, unless if the user has manually pressed the home button, will still the activity will go to this state?
This exception happens when you're trying to add/remove/replace/interact in any other way with a Fragment inside the Activity when it's paused.
Which means Activity will not be able to restore it's state (restore the state of a Fragment which has been changed) if it will be destroyed right away.
Best solution here, is to check that Activity is NOT paused during the interaction with a Fragment.
Another option is to use commitAllowingStateLoss() to interact with Fragment transaction, with a risk of losing it's state.
See:
https://developer.android.com/reference/android/app/FragmentTransaction.html#commitAllowingStateLoss()
In a perfect world you should analyze each crash carefully and add checks to verify that you interact with fragments only when Activity is up and running.
A better explanation is presented in a new Android developer reference and guide documents for using JetPack Life Cycle Listener.
https://developer.android.com/topic/libraries/architecture/lifecycle#kotlin
The library makes the components Activity Life Cycle aware. That means you do not require an abstract baseActivity class which overrides every life cycle callback, and record that state in a boolean variable. LifeCycle listener will do it for you.
All you have to do is stop introducing a new fragment or stop any Loader that updates the UI when its response returns. The right time to do this is before onStop or onSavedInstance state is called, and your components will be made aware of it.
It clearly states that after the onSavedInstancState or onStop is called the UI becomes immutable till the onStart of the Activity is called again. Sometimes you have to call restart the same activity using NEW TASK and CLEAR TASK flags using intent, when this state occurs and there is no chance that otherwise onStart is going to be called.
Happy Coding :-)

Is it possible to edit the content of the parent Activity when using SlidingActivity

I'm creating an app and I'm using a library called "SlidingActivity".
[Github Link]
I actually have two activities. One being the main activity of the app and the other one extending SlidingActivity. So when the SlidingActivity is opened, it's still possible to see the main activity in the background (see the images on the Github page).
Is it possible to edit the content/layout of the main activity when the SlidingActivity is opened?
I tried using getParent() but it's returning null.
Edit: As #Hamza Hathoute suggested I've tried overriding onPause() and onDestroy(). I've seen that onPause() is called each time the SlidingActivity is opened.
Thanks in advance. I'm new to StackOverflow so if there is anything I've done wrong please tell me!
The issue you are facing is one of communication. That is, you want the SlidingActivity to tell the MainActivity that it should change its content. While there are a few approaches to this issue the simplest might be to use the LocalBroadcastManager to send a broadcast.
Edit:
An activity that is not in the foreground can be killed by the OS in low memory situations. So you should register your receiver in onCreate and unregister in onDestroy. It is therefore possible that you might miss a broadcast (if your activity was destroyed when the broadcast was sent).
If you want to cover this case then unless you want to deal with persistence (shared prefs, db) then you should probably use the startActivityForResult option mentioned in another answer. The downside of that approach is that the changes to MainActivity aren't immediate. So if the sliding activity isn't full screen then you won't see changes in the MainActivity.
If you want to show the main activity in the background, you can use a transparent background for the sliding activity.
So, you should pass whatever params you needed from the main activity (not the activity object) using intent, use that to populate your sliding activity (designed with a transparent background).
In the sliding activity, you can save the desired params to modify the main activity when you come back to the main activity.
If your sliding activity always returns some results to the main activity, you can use startActivityForResult,
See here for implemantation: How to manage `startActivityForResult` on Android?
is really the other activity still running or is the activity in the background just a clone of the content of the previous one?
You may check this by overriding onPause and onDestroy and adding a Log Message.
If it doesn't display any message then you definitely can edit it, just pay attention to the performance.

Does launching a new activity destroy my networking Service/AsyncTasks?

I am tinkering and building on Google's own WifiDirect code (https://android.googlesource.com/platform/development/+/master/samples/WiFiDirectDemo/src/com/example/android/wifidirect). I am passing a boolean, and displaying this boolean in a new activity once passed.
I've managed to make a connection, which causes the new activity to be launched, but nothing gets passed.
The demo contains both FileServerAsyncTask (for the GroupOwner), and FileTransferService(client). A few questions:
A. As a groupOwner/Server, when FileServerAsyncTask gets executed,
does it stay active forever?
B. How would a UI ”know” when it has successfully received something,
and should update accordingly? FileServerAsyncTask possesses a
OnPostExecute() section – but how should I update the host activity?
C. Where should I call FileServerAsyncTask? As soon as a contentView
is loaded, as its done in the demo? Would it work if tied to a
button?
As mentioned before, as soon as I make a connection, I start a new activity, with its own UI. This in itself is probably dumb.
A. Is this bad practice? Will it interfere with the networking code within WifiDirectActivity & its two fragments. (As it currently doesnt seem to work properly)
B. Will WifiDirectActivity be destroyed then? Since a new activity is running
C. If this is bad practice, and I should consider using a new fragment, will replacing the two previous fragments somehow affect functionality as well?
I apologize for the composite question!
Code Added
WiFiDirectActivity
https://gist.github.com/EXJUSTICE/25657f080131d4b14528983006fbf272
BroadCastReceiver
https://gist.github.com/EXJUSTICE/0c42da764e26ef8a51417c6a9e5f3a76
DeviceListFragment
https://gist.github.com/EXJUSTICE/ccfb7685f0a5f5dcf599336f79c49ba8
DeviceDetailFragment
https://gist.github.com/EXJUSTICE/e70169b64ac3b7feca3f945164b62781
ConsentActivity (new Activity)
https://gist.github.com/EXJUSTICE/e3b4d581cc3634f9a15809725b66bcf6
FileServerAsyncTask (ripped from DeviceDetailFragment)
https://gist.github.com/EXJUSTICE/850ad02f81c03b29b141b3e19f4515c9
FileTransferService
https://gist.github.com/EXJUSTICE/81780db849729ce2fa0550fdd9db49bf

Restarting activity maintaing state with no animation

When the user clicks a button in my application, it will alter some data in the document being worked on and at that point I want the activity to rebuild its UI. I want to do it this way if possible because exactly what views need to be updated for any given change is going to be tricky to know in advance.
I tried getting the intent, calling finish() on the activity then calling StartActivity with the same intent. Using this method I can disable all the pending transitions, so it's fine except because it creates a new instance of the activity its state can't be recovered (unless I do something really dumb like save it to preferences). And this is not acceptable because the activity contains a ViewPager which using this method returns to page 0 whenever I update something.
Next I tried using Activity.Recreate(). This solves the issue around the state not being saved since it appears to be the same instance of the activity. But in this case I can't work out how to disable all the animations, so there is always a flash on screen.
Is there a way I can make an activity.recreate() call look seamless to the user? Or is there a better way? Since this is all within a viewpager, refreshing the fragment would work just as well, but this not happening from the fragment class itself, but rather many objects which each provide part of the UI.
I faced similar problem, when I invoked recreate on activity it was blinking, I ended up using below code:
// uncomment below line for blink effect :P
// recreate();
// restart activity without blinking :-)
Intent intent = new Intent(MyActivity.this, MyActivity.class);
startActivity(intent); // start same activity
finish(); // destroy older activity
overridePendingTransition(0, 0); // this is important for seamless transition
I know I am too late to answer your question but I hope that it will help other developers who are facing same problem.

Starting an Activity from Notification destroys Parent Activities

I have an app with 4 activities int the sequence say A->B->C->D and a service S that is started by A when the app is started. Now on a particular condition this service triggers a notification which again should start activity C withing my app and with the arguments that C usually needs from B. Also to function properly, C needs to use a static variable from the activity A. That was the setup.
Now what happens is when the notification is triggered from the service S and I click on it, activities A and B are automatically destroyed resulting in a force close(Since my activity C depends on a static variable in A). Why does this happen. I have used a TaskStackBuilder to place C's parent activity(i.e B) onto the stack so that normal back behavior takes me back to activity B.
Can anyone tell me the reason of this behavior. I do not want to run my Activity C as an interdependent task. I want it to be the same instance as that already in the app.
Please help me understand the problem here.
Activity should be independent. It is dangerous that activity C needs to use a static variable from the activity A. Although you create activities in order like A->B->C->D, Android may destroy A/B/C/D when your app is in background, and when user returns to your app, only activity D is recreated.
I encountered the same problem as you once, Starting an Activity from Notification destroys Parent Acitivities. This is because I used TaskStackBuilder. And even after I stop to use TaskStackBuilder, the problem remains. Only after I uninstall the app, it works as expected.
Check the comments for https://stackoverflow.com/a/28268331/1198666
This is happening because the Activity Lifecycle behaves differenty from ICS onwards. This fact answers this question, however I am yet to find out why this is happening. If someone wants to see the code and verify this behavior for themselves, HERE

Categories

Resources