Handle concurrency with asynchronous calls in Android - android

I have the following interface:
interface Callback {
void onSuccess(Result result);
void onFailure(Throwable t);
}
and the method:
void doSomething(Callback callback);
doSomething performs an asynchronous call to a server. The problem is that this method could be called from different components into the Android app at the same time. Taking that in mind, in order to implement doSomething, how can I be sure to return the result to the right callback?
What is happening is that the stored callbacks into doSomething are being replaced with the new requests and the wrong callback is getting the results of other requests.
What are the best practices to solve this?

Related

Android retrofit on response when activity is not active

I am trying to understand what will happen in case my activity isnt in scope when I get response for the retrofit query. I have a list of items in my activity, and I make a request to server and on response, update a few elements in the list. Below is the code.
I have the below retrofit dependency
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
Call<Output> responseCall = APIInterface.getServerRequest(input);
responseCall.enqueue(new Callback<Output>() {
#Override
public void onResponse(Call<Output> call, Response<Output> response) {
//update the data used by adapter.
adapter.notifyDataSetChanged();
}
#Override
public void onFailure(Call<Output> call, Throwable t) {
//nothing much to do.
}
});
I have a few questions.
When the onResponse/onFailure methods are called, are they called in the main UI thread, or are they still in the background thread?
What will happen if my user has moved out of the existing activity, say they moved on to the next activity, or moved back to previous activity, or closed the app altogether. Will my onResponse still get called? And if my activity isnt on the stack and I refer to some variables in there, will I get nullPointerException?
Is it possible, in the response method, to somehow get the reference to latest activity and then call the notifyDataSetChanged on the (maybe) new instance of activity?
enqueue will do the request on a background thread but the callback will be called on the main thread.
The request can return to an unavailable Activity/Fragment there are a few ways to mitigate problems.
If the call is returning to an Activity you need to check if the Activity is still running. There are a few solutions here. Android: how do I check if activity is running?
If the call is returning to a Fragment you can call isAdded() to check if you can mess with the Fragment.
Not cleanly. But that shouldn't be a thing you want. If you want the request to end up in the new Activity then make the request in that Activity.
Here are a few resources:
If you want to set up a cancelable callback that will not return an output if its canceled.
How to Cancel Retrofit request
If want the request to be lifecycle aware you use LiveData<Response<Output>> from your query. What are the benefits of returning a live data of a retrofit response

RxAndroid http request in background using retrofit

To better understand RxAndroid I found this Repo which is full of useful examples using RxAndroid, especially in combination with Retrofit.
So if I look at this part of the repo, I can make an http call by clicking an button which seems to be running in the background right?
What if I have this app which needs to show an activity/fragment and at the same time do some http call on the background and show the data if there is any received?
So for instance I have this fragment with onStart
#Override
public void onStart() {
super.onStart();
pomagistoService
.getAgenda()
.subscribeOn(Schedulers.newThread()) // <- run in background right?
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<Appointment>>() {
#Override
public void onCompleted() { }
#Override
public void onError(Throwable e) { }
#Override
public void onNext(List<Appointment> appointments) {
// show data in ListView
}
});
}
If I start this fragment a ListView instantaneously contains the data which is received by the http call.
Now the question/wondering I have is:
Does this http call run in the background?
I am asking this because of the data which is there immediately when the fragment appears, so I can't really observe it.
Usually, for network request you should use not Schedulers.newThread(), but Schedulers.io(). Also, to get some delay before request is executed and get a chance to see fragment without data try to use .delay(5, TimeUnit.SECONDS) to make 5 seconds delay before call.
if you're using subscribeOn(Schedulers.io()) then you're telling RxJava to do its job in background (another thread).
Schedulers.io() is usaually used for I/O operations like networking, you can use Schedulers.computation() for long processing operations running locally.
and by using observeOn(AndroidSchedulers.mainThread()) you're telling that you want to recieve the final result in the main thread so you can show it or handle ui events.
some common error is the confusion when using subscribeOn() and observeOn(), so to make it easy for you .. you're always want to observe results on main thread to reflect it in UI otherwise use what fit your case.

Global errorHandling solution with RxJava only when onError is not implemented

I have a general error handling solution in my app which should be invoked whenever onError is called. Instead of implementing onError for every subscribe I have done this inside the Application class:
RxJavaPlugins.getInstance().registerErrorHandler(new RxJavaErrorHandler() {
#Override
public void handleError(final Throwable throwable) {
new ErrorHandler().call(throwable);
}
});
However I would like to have the ability to override this by implementing onError, and according to:
https://github.com/ReactiveX/RxJava/wiki/Plugins#rxjavaerrorhandler
This plugin allows you to register a function that will handle errors that are raised by RxJava but that cannot be handled by the ordinary RxJava onError notification process (for instance, if RxJava tries to propagate an error to a subscriber that has not implemented an onError handler).
This should have been the case where I have implemented onError. However when running the code handleError inside RxJavaErrorHandler still gets invoked first, even though I have implemented onError.
Update:
According to zsxwing, the wiki has been updated with the correct description of RxJavaErrorHandler.
What we did at work was make a subclass of observer that has a default implementation of onError that you can still override if need be. Seems to solve your use case.

Android Accelerometer issues

I am working on a game that involves using the accelerometer to control the character. My problem is this: I need to use the values recieved by the sensor in classes and methods that are not accessible inside OnSensorChanged(). I believe I need to implement a Callback from inside the OnSensorChanged, but I don't know how to do that. Can anyone help me out?
I believe the answer in this post (How to Define Callbacks in Android?) will help you out.
To summarize, create the callback interface:
// The callback interface
interface MyCallback {
void callbackCall(SensorEvent event);
}
Implement the call back interface in the class that is supposed to do calculations:
class Callback implements MyCallback {
void callbackCall(SensorEvent event) {
// callback code goes here
}
}
Make the call from your Activity where you have the onSensoreChanged():
// The class that takes the callback
class Worker extends Activity implements SensorEventListener {
MyCallback callback;
public void onSensorChanged(SensorEvent event) {
callback.callbackCall(event);
}
}
I hope this helps.
UPDATE:
I assume you already know about processes and threads (if not, please have a look at the Android doc about Processes and Threads).
The onSensorChanged method is an I/O and it is a good practice to do I/O operations in a separate thread (instead of the main UI thread).
Once the callback method is called, you can store the event in another variable and use those local variables in that class.
Since you are writing a game, it is unlikely for your app to require every single event. Therefore, while the app is busy calculating data for your game, the other events can be dropped. You can do this by setting a "busy" flag (boolean) and include the code for calculation within this if block.
void callbackCall(SensorEvent event) {
if (!busy) {
// Set the busy flag to block other event changes
busy = true;
// callback code goes here
// Once finished, reset the busy flag to allow other events to come in
busy = false;
}
}

Android AsyncTask - Changing listeners

I have an AsyncTask which never dies. The listener to the events in this AsyncTask keeps changing(depending on which activity/fragment is visible to the user). To accomplish this, I have a setup like the following :
An interface :
public interface TaskListener {
public void onItemChanged(String itemName)
}
AsyncTask which contains a TaskListener Member variable which is registered/unregistered using public methods.
public void registerListener(TaskListener listener) {
mListener = listener;
}
public void unregisterListener() {
mListener = null;
}
In the onPublishProgress() method (called via publishProgress() in the doInBackground() method) of the AsyncTask, I notify the listener.
Now, my question is are there any caveats for this situation while notifying the listener? In particular, I would like to know whether it is thread safe or not. i.e., if publishProgress() and registerListener() is called at the same time, will the right listener receives a callback?
I once had to debug an AsyncTask and followed my code even got into android's source code.
publishProgress() does not issue a direct call to onProgressUpdate() it just posts a message in a queue, and the queue handler eventually calls onProgressUpdate().
So strictly speaking, if publishProgress() and registerListener() are called at the same time registerListener() will get there first.
If you are concerned about interference between the two, just enclose the sensitive code in a synchronized block over whatever variable is there.
synchronized(mListener) {
// do stuff to mListener
}
do this in both onProgressUpdate() and registerListener() and anywhere else you want to be mutually exclusive on handling the listener.
AsyncTask should not live between activities. That's not really correct way.
Android has services for this.
http://developer.android.com/reference/android/app/Service.html
http://developer.android.com/guide/developing/tools/aidl.html

Categories

Resources