Understanding GMS Task callbacks (Firebase Messaging context) - android

I'm having hard time finding clear explanation of callbacks behavior for https://developers.google.com/android/reference/com/google/android/gms/tasks/Task
We can have whole bunch of them:
on complete
on success
on failure
on cancel
Questions (Firebase messaging context):
a. Is it safe to assume when FirebaseMessaging.getInstance().getTask() fails, on complete will be called with isSuccess false?
b. Will on complete be called in case of hypothetical cancellation scenario (not sure if applicable), again, with isSuccess false?

Related

Firebase Cloud Function call on Android randomly throws an "Internal Error" exception

I call a Firebase Cloud Function from my app and most of the times it works normally, but from time to time (I would say twice a day) an invocation, after a long time, produces an "Internal Error" exception.
Apparently the invocation is not even done, because no record of the function's execution is registered in the Firebase logs on the server. To confirm this, I tried to call another very simple cloud function (see below) just after the ocurrence and this invocation also fails.
const functions = require('firebase-functions');
module.exports = functions.https.onCall((whatever, context) => {
return true;
});
This situation happens only when the app is running on Android devices.
I´ve already tried to implement the retry strategy suggested here: https://cloud.google.com/storage/docs/retry-strategy, to no avail. I´ve implemented a timer to forcibly cancel the task, so the retry strategy could be implemented, but no matter how many times I repeat the invocation, it always fails.
I suspect the connection with the Firebase server is somehow being lost. How can I force a reconnection? Is there anything else I can do to solve this problem?
The app is still under development (the load on the Firebase servers is minimal and sporadic), but I´m afraid I won't be able to launch it until I solve this problem.

Difference between launchWhenStarted and repeatOnLifecycle(STARTED) in collecting flows

As launchWhenStarted and repeatOnLifecycle(STARTED) provide completely different functionality (launchWhenStarted suspends the execution of the coroutine, and repeatOnLifecycle cancels and restarts a new coroutine), if the names of the new APIs were similar (for example, using launchWhenever for the restarting APIs), developers could’ve got confused and even use them interchangeably without noticing.
source
What is a simpler explanation for when to use which?
launchWhenStarted is just a one-time delay.
repeatOnLifecycle creates a suspending point that acts as a handler that runs provided block every time the lifecycle enters provided state and cancels it whenever it falls below it (so for STARTED it happens when it gets stopped).
Update:
For more information: https://medium.com/androiddevelopers/repeatonlifecycle-api-design-story-8670d1a7d333
repeatOnLifecycle restarts its coroutine from scratch on each repeat, and cancels it each time lifecycle falls below the specified state. It’s a natural fit for collecting most flows, because it fully cancels the flow when it’s not needed, which saves resources related to the flow continuing to emit values.
launchWhenX doesn’t cancel the coroutine and restart it. It just postpones when it starts, and pauses execution while below the specified state. They plan to deprecate these functions but I suspect there will need to be some replacement if they do, for the case where you are calling some time consuming suspend function and then want to do something when it’s done, like starting a fragment transaction. Using repeatOnLifecycle for this would result in redoing the time consuming action.
A cold flow backed by a channel or using operators with buffers such as buffer, conflate, flowOn, or shareIn is not safe to collect with some of the existing APIs such as CoroutineScope.launch, Flow<T>.launchIn, or LifecycleCoroutineScope.launchWhenX, unless you manually cancel the Job that started the coroutine when the activity goes to the background. These APIs will keep the underlying flow producer active while emitting items into the buffer in the background, and thus wasting resources.
To solve this issue with these APIs, you’d need to manually cancel collection when the view goes to the background. but it sounds to be a boilerplate code.
That's why Google recommended repeatOnLifecycle(Lifecycle.State.XXX) to make it simple and safe.
repeatOnLifecycle is a suspend function that takes a Lifecycle.State as a parameter which is used to automatically create and launch a new coroutine with the block passed to it when the lifecycle reaches that state, and cancel the ongoing coroutine that’s executing the block when the lifecycle falls below the state.
Learn more from here

calling AccountManager#getAuthTokenByFeatures from multiple WorkerThreads at the same time

Background
I am using AccountManager with a custom account type. In the beginning the App starts the user LogInActivity and a token recieved by the server is stored within the account. The tokens are used by some Worker organized by WorkManager to sync data in the background. Each worker is requesting the token with AccountManager#getAuthTokenByFeatures(). When the user is changing the password on the website connected with the server, the token is expired and the AccountManager is starting (due to password change) the related LogInActivtiy.
Issue If during the user input of the new login data other (parallel running) Worker are requesting an AuthToken, the LogInActivity is started multiple times.
Solution Approach
Setting android:launchmode="singleInstance"of LogInActivity -> only one Activity is started, but second, third, ... calling Worker results in deadlock due to no return of AccountManagerFuture<Bundle>.
Creating Workaround: AccountAthenticator checks if an Instance of LogInActivity is allready running in Foreground and starts all further Activities invisible in the background. If LogIn was successfull all in the background running LogInActivities recieving necessary Information via LocalBroadcastManager -> LocalBroadcastManager is deprecated, power consuming and unnecessary overhead
Is the use of AccountManager in combination with WorkManager correct in this case?
Might there any configuration issue with AccountManager causing this behavior?
Any other solution approaches?
Help is really appreciated. Thank you!

Rx: Should API calls be Singles or Observables of Started, Success, Error events?

Should API requests be Single or rather Observable of Started, Success, Error events (with onError should never occur)?
Current state is IntentService with Started event posted by EventBus, synchronous api call, Success event or Error event.
The latter sounds ike a better fit, but then how would one do say saving to database after the api call? I would have to have if instanceof Success in doOnNext. Feels weird. How do you guys usually do this?

Fallback observer for custom eventbus with RxJava / RxAndroid?

I am currently researching for better ways to handle events in my app.
Currently I have multiple listeners that are subscribing and unsubscribing to interesting objects on different events.
E.g. on a button click a listener is created, that listens on a client object, if a operation succeeded (in that case it automatically unregisters itself) or if a non fatal error occurs (in that case it automatically retries the operation).
The client object in turn is starting a android service that can emit different status events, that should result in the user interface updating itself or alternatively show notifications, if the app is currently not visible.
In my app I have a really big listener clutter, that is not easy to follow and that is not working on all occasions.
To resolve this issue I would like to implement a event bus with RxJava that hopefully reduces the complexity of my application.
The problem:
Is it possible with RxJava to have a fallback observer for a observable, to react to events, if no other observer is available?
E.g. All activities/fragments register themselves to get informed about certain events, so they can update the UI, if necessary.
When a activity/fragment is created/destroyed it automatically registers/unregisters itself from the event bus.
If the app is now in background, there should be no observers registered anymore. In that case only I would like to use a fallback observer that is handling those events.
I would like to achieve the following:
If in foreground: On event, update the UI.
If in background: On event, show toast / notification.
In my opinion your app shouldn't show anything when it's in the background (user is not interested in it anymore, or is doing something else, so don't spam him with toasts (as he probably would not even know which application raised this toast)).
However,
You can solve this problem with Subject. Let say you have MyServiceErrorHandler class with PublishSubject> inside, so every time there is some part of UI is visible and capable of showing error is should be subscribed to this subject. Then you can expose method like onError(Throwable t) which will call subject.hasObservers(). If yes it pushes data to subject (so it will emit an event to currently subscribed UI) if no you can do some fallback thing (like displaying toast/notification/logging something/etc). This solution is however error prone to rotation as you may receive your result while screen is rotating (thus not subscribed yet)
You can extend this approach a little bit and use a BehaviourSubject which will replay it's last event for every subscriber (pretty handy in case of screen rotation). So you're posting event to this subject even though there are none subscribers, and when user opens this app back again (and one of your UI element will subscribe) it will receive last event with error (so you can show it properly). But in that solution you would need a little bit more logic to clear this subject in case of obsolete/already consumed errors (to prevent it from showing on every rotation/etc).

Categories

Resources