After reading many SO threads and answers about proper Activity-Fragment implementation for long running tasks, I currently have an activity adding a UI less Fragment to it thru a FragmentTransaction and letting it run on its own retaining its instance state.
But the problem seems to start off when the "Google Drive Android API" object's Connect method is called (thereby causing a onConnected call) and then the activity going thru a restart due to screen rotation or so.
Now, having a fragment handling the drive mechanism, it causes the fragment to work properly, but many of the drive api calls require a CONTEXT (in the form of activity) to tie back to.
As a result, at a given fraction of time, when the activity is being restarted and fragment is being detached and reattached, there is no guarantee that the getActivity() call would return a correct activity context.
The drive api (inside the onConnected or within some other result callbacks) thereby fail, as they don't have an activity to tie back to.
How to handle such a scenario? Is there a way to tell the drive api to wait while the activity is being recreated?
I can post my code, if that helps, but think this is a pretty generic scenario in handling screen rotations when using drive api for android.
Related
As Android added last year , Run time permission thing in Android API version 23 and above, I have a query regarding
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
And
ActivityCompat.requestPermissions(new String[]Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
api for requesting permission. In above library either we have to provide Activity instance which should have implemented ActivityCompat.OnRequestPermissionsResultCallback interface. Support version of fragment and AppcompatActivity, FragmentActivity have implemented this by default.
Why we need to provide the callback refrence in form of Activity or Fragment only? We could have design this API as
ActivityCompat.requestPermissions(context,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS,ActivityCompat.OnRequestPermissionsResultCallback callback);
I mean we have bound to provide a Activity or support version of Fragment. What if we want to check outside activity in any other simple class? Just a case I have a GeofenceManager class which needs Location permission and many Activities or classes need some information from this GeofenceManager singleton class.
Should I have to implement OnRequestPermissionsResultCallback in each of activities? I think it would be much better if the Api is in suggested design above. There must be some big reason in designing the API in that way. My little experience does not able to get it.
All the AppCompat APIs are meant to be as easily as possible replaced by their native counterpart.
Said that the native android.app.Activity on API 23 implementation is a public final void requestPermissions method and a public void onRequestPermissionsResult callback.
So that how those gets translated to AppCompat. Having them as separate entities would certainly lead to a more flexible approach, but it would also lead to being unable on the future to deprecated the AppCompat as devices get updated.
You could argue why the API23 activity doesn't do the same, but that's just in general how Android always being and is their approach to everything, example onActivityResult
Furthermore those must be attached to the activity because an should only ever ask for permissions when it's in foreground.
edit:
Further thinking, there's another reason for it. Rotation!
With the activity being destroyed and re-built during rotation, having a callback based on an interface can be very tricky.
The callback method need some type of context or carry further actions (go to the next activity, or load/read something from the newly granted permission). So if the coder pass the interface as an anonymous inner class or make its activity extend that interface and a rotation happen, it will leak the activity. Or the callback method would need to receive a context parameter, but then the framework would have to keep track on which activity is the current context to send back to the callback. All this would get very convoluted very fast. So a simply straight forward way of doing it is by making it an actual method of the activity.
I know it is a bit late to answer my own question, but I still think my answer will help this thread.
In Android, there are 5 types of process, based on priority in general. These are foreground processes, followed by any visible processes, service processes, background processes, and finally ‘empty’ processes.
The foreground process has the highest priority as in most cases the user is directly playing with these process's components, like Activity or foreground services. But our case falls in the second kind of process. A Visible process.
Note: The permission dialogs are not shown in the activity which requested permission. It is, in fact, an Activity!
There are situations where your activity can be visible but not in the foreground. A simple example is when the foreground activity starts a new activity with Dialog theme or a translucent activity.
But Keep in mind though, just because you are visible does not mean you can’t be killed. If there is enough memory pressure from foreground processes, it is still possible that your visible process will be killed. From a user perspective, this means the visible activity behind the current activity is replaced with a black screen. Of course, if you’re properly recreating your activity, your process and Activity will be restored as soon as the foreground Activity is closed without any loss of data.
The fact that your activity and process can be killed even if visible is one of the reasons the startActivityForResult()+onActivityResult() and the requestPermissions()+onRequestPermissionsResult() flows don’t take callback class instances — if your whole process dies, so does every callback class instance. If you see libraries using a callback approach, realize that it will not be resilient to low memory pressure cases.
Note: Android only kills processes, not components. Always remember this.
That is one of the main reason why requestPermission() API in Android is designed the way it is, instead of the one mentioned in question by me.
Currently in the app I'm working on network requests are made with ASyncTasks inside of headless retained fragments (references: 1 2) to handle device rotation, etc. It feels pretty hacky (aren't Fragments supposed to be "reusable UI components"?) but works as advertised. So far so good.
The problem now is that I'm modifying the app to support tablets which means converting most Activities into Fragments. Currently the Activities that make API calls try to reattach their "worker fragment" after config changes to see if the API call is already in progress or has already completed.
This doesn't work when an Activity is converted to a Fragment because it would be accessing the Fragment Manager of its host activity - which may be hosting more than one fragment!
After some research it looks like I could use nested fragments (https://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager()) introduced in API 17 to continue with this approach. To me this feels like it's getting a bit out of hand - there must be a simpler way.
Long story short - what's a simple approach to making API calls from fragments that gracefully handles device config changes? I'd imagine most tablet apps out there do this; so if you've built a tablet app, how do you go about it?
Please look up
Fragment#setRetainInstanceState(true)
this way you can ensure the Fragment is retained across configuration changes.
I have a complex app that has background threads (that could be in a service) which, when they receive data from the internet, need to notify my main display activity (to update on of several status indicators). All run in the same process (I see no reason to do otherwise).
However, in some circumstances, these events are frequent - 5 per second. Also, the events may occur when the activity is not-visible or even destroyed. I think the only thing novel about this question is the issue of efficiency. I still target the G1, for example.
There are a number of methods mentioned in this thread, but I don't know which of these are efficient enough, and will work if the activity is destroyed. Those methods are the "Android way" which I would prefer to follow.
I have three ugly anti-Android ways that work, but they also have drawbacks:
Have a thread in the activity that is waits on a semaphore, and when released, does the update. Disadvantages: extra thread, how to handle several event types
Like #1, but use a concurrent blocking queue object. Disadvantages: extra thread, same type of event may end up in the queue multiple times (not good)
Keep a static reference to a handler on the activity, and use that to run an updater. Disadvantages: (a) may leak a reference to the activity? (b) what happens when the activity changes state? (c) multiple runnables could end up there when only one is needed.
Also, the events may occur when the activity is not-visible or even destroyed.
If your activity is destroyed, there is nothing to update. If and when the user elects to re-visit that activity, the activity can get the current information in onResume() for display.
If your activity is in the background, there is nothing that needs to be updated, either. Again, if and when the user elects to re-visit that activity, the activity can get the current information in onResume() for display.
The ONLY time you need an activity to be notified of events in real time is if that activity is in the foreground. In that case, any of the solutions I outlined in the answer you linked to could work. The binding option or Messenger are probably the lightest-weight solutions.
I have a complex app that has background threads (that could be in a service)
Not "could be" -- "must be", if they are to live beyond the scope of any given activity instance.
I have three ugly anti-Android ways that work
None of those work without potential memory leaks.
Here, Dianne says that the old methods of retaining objects via onRetainNonConfigurationInstance() are now made obsolete by the fact that you can retain Fragment instances over configuration changes.
And here, in the API Demos for fragments, it shows how to use this method for maintaining threads after a configuration change.
I see that during a configuration change, when the Fragment might not be attached to any activity and the thread is done doing it's work, it's able to call wait() so that it doesn't try to deliver results while an Activity isn't attached. I find this very useful, and a great way to mitigate one of the more pain-in-the-butt problems with Android orientation changes.
However, if you're using a threaded library (an API library that uses a thread executor, for example), where you don't have access to wait() on said threads, how could we use this new feature to our advantage?
How can we ensure that messages won't be delivered while an activity is not attached?
I've been thinking of a way to maybe queue up messages and delivery them when a new Activity is attached, but I wanted to hit up you guys and see if you've already come up with some solutions.
Also, note, I've looked into the LoaderManager API, and it seems like it would be good for data that needs to be loaded when an Activity is shown, but not for something event based, like logging in via a button, etc.
You could get around this issue using a higher level concurrency utility such as a Latch, which you could have all of your threads wait on until the new Activity is attached (just before they try to access the message queue to deliver their result).
Once the Activity is attached, you can release the Latch, allowing all the threads to deliver their results.
I've been bugged by this for a while. How do I properly handle screen orientation changes while I have a separate Thread / AsyncTask running? Currently, I have
android:configChanges="orientation|keyboard|keyboardHidden"
in my AndroidManifest.xml, but that is not really encouraged:
Note: Using this attribute should be avoided and used only as a last-resort. Please read Handling Runtime Changes for more information about how to properly handle a restart due to a configuration change.
Also, in the 2.3 emulator, it works when switching to landscape, but switching back to portrait fails.
Now, the reason why I use configChanges is because when the user switches orientation, I might have an AsyncTask running, doing some network traffic, and I don't want it stopped.
Is there any other way of doing this, or is there a way of fixing 2.3 to switch back to portrait?
I know about onRetainNonConfigurationInstance, but I'm not sure it would be a good idea to "save" the AsyncTask instance, mainly because the class that extends AsyncTask is not static (so it is tied to the Activity) -- and it needs to be, because in onPostExecute() it calls methods from the Activity instance.
I had a similar problem to your and worked around it by implementing the AsyncTask as part of a class which inherits from Application class. An Application class is available all the life time of the application So you don't have to worry about your AsyncTask getting interrupted unless the whole application will be killed.
To get notified when the task has finished the Activity has to implement a interface which it uses to register itself to the Application class.
When your application is destroyed because of the screen rotation you can unregister your Activity from the Application class and re-register it when it is recreated. If the task finishes between destruction and recreation the result of the operation can be stored in the Application class meanwhile so the Activity can check whether the task is still running or whether the result is already available when it is recreated.
Another advantage is that you have direct access to the applications context because the Application class is a sub class of the Context class.
Take a look the droid-fu library BetterAsyncTask. It is meant to handle this exact case.
http://brainflush.wordpress.com/2009/11/16/introducing-droid-fu-for-android-betteractivity-betterservice-and-betterasynctask/
I already popped up similar question here.
Basically there is an example of how to pause/resume an AsynTask on device rotation. However it still does not fit for all cases (sometimes it is not possible to safely suspend the action, such as a new user creation on a remote server). For those "unsafe" cases you need to code somewhat I'd call a tricky "framework". You will see CommonsWare gives github links to the one.