Is it safe to use the ApplicationContext for a Dialog? - android

I'm running an application that generates a dialog alert from within a Fragment as a network callback. This requires you to pass in an available Context reference; since I'm using Fragments, I use getActivity(). Due to the network-dependent nature of the callback, getActivity() can sometimes return null. This crashes my code.
To work around this error, I was hoping to supply the ApplicationContext to the dialog instead. It is a singleton that persists for the lifetime of the application, so I know it won't be withdrawn. In addition, the Dialog's content is with regards to payment confirmation, so I believe there's reasonable scope for it to be displayed without a strict relationship to a certain Window.
Is this a safe implementation? Am I avoiding the inevitable, and should move to a more robust pattern altogether?

Is this a safe implementation?
IMHO, no.
Tactically, I would expect your app to crash in some situations (e.g., your app is in the background at the time the network I/O completes), and I would expect your dialog to not necessarily honor the appropriate theme. Since it seems like your "dialog" is not tied to an activity, it should be an activity, in the form of a dialog-themed activity. That solves your reliability problem and your theme problem, though there is still the possibility that you display a dialog(-themed activity) while the user is in some other app, if your network I/O takes longer than you anticipate.
Strategically, it seems like you care about the results of your network I/O regardless of what happens in the UI layer of your app. In that case, your UI layer of your app should not be the one directly receiving the results of the network I/O, and it feels like your fragment is doing that right now. Use something that is decoupled from your UI (IntentService, JobService, bare thread, ThreadPoolExecutor) for managing the network I/O. Have it use an event bus (LocalBroadcastManager, greenrobot's EventBus) to tell the UI layer that the network I/O completed, and if the UI layer does not respond to the event (because it is in the background and you only pay attention to events when the UI is visible), raise a Notification or do something else subtle to let the user know about the results.

You have to use an Activity as Context for your Dialog, because Dialog is a component, that expects the UI context. So before showing the dialog, you can check if the current fragment is currently added to its activity using the isAdded() method:
if (isAdded()) {
showDialog();
}

Related

Network call when exiting the screen - Android coroutines

I am trying to implement a UI in a fragment, where user can make all sorts of updates and I need send it over to backend when user EXITS the screen. (Batch update)
I am using MVVM pattern, where network calls are performed from viewmodel . Now, viewModelScope.launch won't work here, since as soon as user exits, the coroutine is canceled by onCleared().
For now, I added GlobalScope and it works but I have also come across this and this question
Are there any other alternatives to accomplish this with Coroutines?
Coroutines are mostly recommended for work that should start immediately and is scoped to the lifecycle of a Fragment, Activity, ViewModel or any other object with a lifecycle. Since the rest of the coroutine builders are tied to scopes, they wont accomplish what you are trying to do, since the user might leave your app at any given time.
A better approach would be using WorkManager with CoroutineWorker, which isn't tied to your UIs or App lifespan and still takes the advantages of working with Coroutines. With WorkManager, your work could be enqueued when the user leaves your designated screen and will be guaranteed to run once the constraints you specify are fulfilled (for example having internet connection). I recommend you to check Android's Guide to background processing if you are still making up your mind on which solution to use.

Android Run time permission api "requestPermission()" design

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.

Always use services in android?

I've read by many people to not use AsyncTask for web requests, but rather use IntentService, since AsyncTask is bound the lifecycle of its activity. is that always the case? cause I'm making a social media app, And I wonder if each action the user makes should launch a service (for example, press like, add comment, etc)?
Do not use AsyncTask, as you may have read, it is problematic on Activity recreate. However, you may use AsyncTaskLoader with LoaderManager, which is designed to fix the problem.
And there is one point you are wrong with IntentService, you do not launch a service everytime using IntentService. You are submitting requests to the same service only (unless it is being killed), and the IntentService pull requests from the stack.
I tend to use a mixture of both. I use an IntentService when requesting/posting data from a server, then deserialising it and storing it locally. All this could take several seconds depending on the amount of data returned and the server's response time.
I would use an AsyncTask within an activity if I know that the request is going to be very quick. I use it for more fire and forget small tasks.
The important thing to bear in mind is that your AsyncTask is tied to your activity. And if your activity gets destroyed (due to an orientation change etc.) then you could easily have an NPE in the onPostExecute().
If the task you wish to perform is specific to a Context and is considered garbage once you leave the Context, such as if you consider the user session to be invalid once they leave, then an AsyncTask is a good choice.
However, if the task is specific to a context and may take a long time to perform and you want the user to be able to leave and come back later to see the result, a service may be well suited even though the task is specific to a Context.
If the task you wish to perform is applicable outside the scope of a Context, then a service may be better suitable.
If you just always use a service, you'll probably be over complicating your code.

Which should I use Handler, AsyncTask or Thread?

This may be a common question but I couldn't find my exact scenario. I understand that its down to developer choice in a lot of ways but I don't know enough to choose best.
I have my initial app splash screen which will just display a logo whilst checking the user is logged in. If their login details are already stored in a sharedPreference then I want to check those details against my online database of details for verification. Once this is all checked I'll either pass the user through to the main app screen or a registration screen.
So when doing this check of user details, and then verifying them. Should I do this in a separate or use a handler? I don't think AsyncTask is needed as I'm not wanting to pass any progress details back to the UI?
TIA
I suggest using AsyncTask.
First of all, because AsyncTask is a complete threading framework (that uses Thread and Handlers behind the scenes) that allows for a nicer control of single thread operations. Including cancel() for example, in case the user decices to leave the application before the splash screen is done.
I don't think AsyncTask is needed as I'm not wanting to pass any
progress details back to the UI?
actually, yes you do, even to start the new activity (either Login or AlreadyLoggedIn) you have to call startActivity() from the UI thread
You should probably do this in a separate thread because it is network activity. IntentService is a good option. I think your main concern is that whatever method you choose needs to work even if the user rotates the screen and the activity is destroyed and recreated.
Maybe use a Fragment for the splash screen with setRetainInstance(true), so it will get reattached to the activity after configuration change. Then you can either pass the service a Handler (or a Messenger to be more accurate), or have the service send out a broadcast intent when it finishes working.
When to use an Async Task?
AsyncTask helps in offloading memory intensive/blocking call to a background thread while, your UI operations can still carry on in the UI thread.
If any operation blocks the UI thread for more than 4-5secs, you might also get an ANR(Android Not Responding) dialog. AsyncTask come handy when you want to update the UI after doing the process (onPostExecute) and also before starting it (onPreExecute).
Using a Thread
Whatever you do in doInBackground using an AsyncTask can also be achieved using a Thread. But incase you need to do any UI operation you will need to use a Handler or runOnUiThread to accomplish your task. Refer to Painless Threading in android in case you wish to use threads.
Also what Budius said is true.
In your case you can use an AsyncTask to check for user creds in sharedPref and then appropriately authenticate with your middleware and finally in onPostExecute navigate to a new activity.
In the meanwhile you can show a progress bar to the user signifying the on going auth process.
To add on to that. I had a very similar situation where I had to verfiy a users login (which was stored in the phone) in the background from a "home screen". I used the IntentService ResultReceiver pattern. At first it took a bit for me to get up-to-speed on it, but once its implemented its very simple to manage.
Basically, you start the activity that is your intent service, passing it any parameters that are needed (username, password, etc...). In my case it was a separate class that used REST to verify the user. Once the REST class has done its work, the ResultReceiver method onReceiveResult, returns back the data to the UI activity from the REST activity.

Android runOnUiThread - how to pass the Activity

I'm writing a XMPP Client using SMACK.
So when I want to update my contactList - the ListAdapter.notifyDataSetChanged requires to be run in the UI thread, but obviously the SMACK Library uses Multithreading on the RosterListener (which in fact is a good thing). But here is the problem: to run s.th. in the UI thread, I need a valid context.
But how do I get it? Passing the Context of the Activity down to the register function of the RosterListener was the first that came to mind - but I have some functions in different classes there before I even get to the register function, and I don't really like it to pass the context over and over again until it finally reaches its destination, where it will be used.
I guess, I'm not the only one, who has encountered this problem, so how would you solve it?
Maybe a Singleton, just to save this one Context (in my opinion an even less favourable idea...)
Or is maybe my whole design flawed?
Is there a possibility to get the UI thread from anywhere?
Bottom line: I don't really have a clue how to handle it, at the moment I'm passing the context as argument through multiple functions, but is there a better way to do it.
Thanks for any help.
Put XMPP code into Service and then send broadcasts. Interested Activities can simply register for those broadcasts. That way you'll never again worry about UI thread and availability of Activity context.
I found a neater and more modular way of doing it. For this you need to have defined an Application Context. Once you have that, you can call RunOnUIThread from any class library without the mess of having a reference to the Activity.
From anywhere within your class library call:
Handler handler = new Handler(Application.Context.MainLooper);
handler.Post(() => doStuff());
Please bear in mind that this is written in C# as I use MonoDroid, but I believe it is very similar to Java.
For how to create an ApplicationContext look at this thread
I do not get what exactly you try to do but if you are in some thread and you want to shitch back to UIThread than
Looper is your solution
http://developer.android.com/reference/android/os/Looper.html
Reading you, I get a feeling like you are working with callbacks. Smack or whatever that is is calling you back from a worker thread, and you want to post to the main UI thread when that happens.
In my experience, callbacks can always be associated to a custom piece of data, which you pass when registering the callback, and receive when you are actually called back.
In your context there are two approaches which I consider to be poor design:
using any kind of global thingy, call it a singleton if you like
let your Model expect and return the (Android-and-UI-specific) Context
Instead, I would create a small interface which is implemented by the Activity, have the Model accept an instance of this interface, and yes pass it over the different layers until registration.
The methods exposed by this interface will be called asynchronously, which you could document appropriately, to indicate that runOnUiThread() or similar must be used.
This way, you're not exactly passing the Context (which is a platform and UI detail) all over the place and into the Model. Plus, you avoid global/static data, which leads to various problems, conflicts and other memory leaks.

Categories

Resources