Return value from thread (runnable) - android

I'm working with Room to persist data, the new AAC for persisting data, and I work on an app where the Todo app provided in the Google's github repository serves as our blueprint.
I've been trying to get a value returned by a transaction performed on an entity. I used a global variable mCategories to retrieve and store the data returned but I keep on having a null object being returned.
Here's my code:
public interface LoadDataListener<T>
{
void onReadTransactionCompleted(T arg);
}
private void readTransaction(final LoadDataListener<List<Category>> loadDataListener, final boolean onlyClassic)
{
Runnable readRunnable = new Runnable() {
#Override
public void run() {
List<Category> categories;
if (!onlyClassic)
categories = mCategoryDAO.loadAllSellingCategories();
else
categories = mCategoryDAO.loadAllClassicCategories();
LOGD(TAG, "Category size: "+ categories.size());
// The log above reads a value > 0
loadDataListener.onReadTransactionCompleted(categories);
}
};
mAppExecutors.diskIO().execute(readRunnable);
}
private List<Category> getSanitizedAndPersistedCategories(boolean onlyClassic) {
readTransaction(new LoadDataListener<List<Category>>() {
#Override
public void onReadTransactionCompleted(List<Category> arg) {
mCategories = arg;
LOGD(TAG, "sanitizeCategoriesList size before: " + mCategories);
// The log above reads a value > 0
}
}, onlyClassic);
LOGD(TAG, "sanitizeCategoriesList size after: " + mCategories);
// The log above reads null
return sanitizeCategoriesList(mCategories);
}
What am I missing here ??

That's because you have 2 threads here.
When you call readTransaction() and then mAppExecutors.diskIO().execute(readRunnable), method readTransaction() returns immediately and calls LOGD(TAG, "sanitizeCategoriesList size after: " + mCategories);, which as expected prints null. In the meantime, asynchronously on second thread, run() is executed, invoking at the endonReadTransactionCompleted() and finally setting mCategories value.
So you can only rely on mCategories after onReadTransactionCompleted() was invoked.
If you are using mCategories for UI related stuff, you might wanna consider using AsyncTask and moving your code from run() to doInBackground() and code from onReadTransactionCompleted() to onPostExecute()

Related

Android: infinite scroll with rx-java using repeatWhen, takeUntil and filter with retrofit

I am using Retrofit 2.2 with RxJava.
The pagination works like this: I get the first batch of data, I have to request the second batch of data with the same params except one which is the lastUpdated date and then if I get empty or the same batch of data it means there are no more items. I have found this great article https://medium.com/#v.danylo/server-polling-and-retrying-failed-operations-with-retrofit-and-rxjava-8bcc7e641a5a#.40aeibaja on how to do it. So my code is:
private Observable<Integer> syncDataPoints(final String baseUrl, final String apiKey,
final long surveyGroupId) {
final List<ApiDataPoint> lastBatch = new ArrayList<>();
Timber.d("start syncDataPoints");
return loadAndSave(baseUrl, apiKey, surveyGroupId, lastBatch)
.repeatWhen(new Func1<Observable<? extends Void>, Observable<?>>() {
#Override
public Observable<?> call(final Observable<? extends Void> observable) {
Timber.d("Calling repeatWhen");
return observable.delay(5, TimeUnit.SECONDS);
}
})
.takeUntil(new Func1<List<ApiDataPoint>, Boolean>() {
#Override
public Boolean call(List<ApiDataPoint> apiDataPoints) {
boolean done = apiDataPoints.isEmpty();
if (done) {
Timber.d("takeUntil : finished");
} else {
Timber.d("takeUntil : will query again");
}
return done;
}
})
.filter(new Func1<List<ApiDataPoint>, Boolean>() {
#Override
public Boolean call(List<ApiDataPoint> apiDataPoints) {
boolean unfiltered = apiDataPoints.isEmpty();
if (unfiltered) {
Timber.d("filtered");
} else {
Timber.d("not filtered");
}
return unfiltered;
}
}).map(new Func1<List<ApiDataPoint>, Integer>() {
#Override
public Integer call(List<ApiDataPoint> apiDataPoints) {
Timber.d("Finished polling server");
return 0;
}
});
}
private Observable<List<ApiDataPoint>> loadAndSave(final String baseUrl, final String apiKey,
final long surveyGroupId, final List<ApiDataPoint> lastBatch) {
return loadNewDataPoints(baseUrl, apiKey, surveyGroupId)
.concatMap(new Func1<ApiLocaleResult, Observable<List<ApiDataPoint>>>() {
#Override
public Observable<List<ApiDataPoint>> call(ApiLocaleResult apiLocaleResult) {
return saveToDataBase(apiLocaleResult, lastBatch);
}
});
}
private Observable<ApiLocaleResult> loadNewDataPoints(final String baseUrl, final String apiKey,
final long surveyGroupId) {
Timber.d("loadNewDataPoints");
return Observable.just(true).concatMap(new Func1<Object, Observable<ApiLocaleResult>>() {
#Override
public Observable<ApiLocaleResult> call(Object o) {
Timber.d("loadNewDataPoints call");
return restApi
.loadNewDataPoints(baseUrl, apiKey, surveyGroupId,
getSyncedTime(surveyGroupId));
}
});
}
As you can see the interesting method is loadNewDataPoints and I want it to be called until there are no more datapoints. As you can see Observable.just(true).concatMap is a hack because if I remove this concat map the restApi.loadNewDataPoints(....) does not get called although in the logs I can see that the api does get called but with the same old params and of course it returns the same results as the first time so syncing stops, saveToDataBase does get called fine. With my hack it works but I want to understand why it does not work the other way and also if there is a better way to do this. Thanks a lot!
So, I've written this kind of APIs (it's called Keyset Pagination) and implemented Rx clients against them.
This is one of the cases where BehaviorSubjects are useful:
S initialState = null;
BehaviorProcessor<T> subject = BehaviorProcessor.createDefault(initialState);
return subject
.flatMap(state -> getNextElements(state).singleOrError().toFlowable(), Pair::of, 1)
.serialize()
.flatMap(stateValuePair -> {
S state = stateValuePair.getLeft();
R retrievedValue = stateValuePair.getRight();
if(isEmpty(retrievedValue)) {
subject.onComplete();
return Flowable.empty();
} else {
subject.onNext(getNextState(state, retrievedValue));
return Flowable.just(retrievedValue);
}
}
.doOnUnsubscribe(subject::onCompleted)
.map(value -> ...)
Here
getNextElement performs the network call based on a state and returns a reactive stream with a single value
isEmpty determines whether the returned value is empty indicating end of elements
getNextState combines the passed-in state with the retrieved value to determine the next state for getNextElement.
It will work correctly if an error occurs (it will be propagated) and if you unsubscribe before the end (queries will get terminated).
Of course, in your specific case these don't need to be separate methods or complex types.

In method my List has elements, but when I get out the list is empty

I am using Back4App which is basically what the old parse.com used to be. I have this piece of code wherein the done method my public List has 5 elements like it's supposed to have. Then once I get out of my method the list is empty.
ParseQuery<settings> query = ParseQuery.getQuery(settings.class);
query.whereEqualTo("Username", MainActivity.Display_Name);
query.orderByDescending("createdAt").setLimit(1);
query.findInBackground(new FindCallback<settings>() {
public void done(List<settings> settingsList, ParseException exception) {
for (settings i : settingsList) {
if (exception == null) {
creationDate = i.getCreatedAt();
settingsFrameNumber = i.getFramesPerHive();
settingsArray.add(0, String.valueOf(settingsFrameNumber));
settingsHiveNumber = i.getHiveNumber();
settingsArray.add(0, String.valueOf(settingsHiveNumber));
settingsHiveBodyNumber = i.getHiveBodies();
settingsArray.add(0, String.valueOf(settingsHiveBodyNumber));
settingsSuperNumber = i.getSupers();
settingsArray.add(0, String.valueOf(settingsSuperNumber));
settingsYearsOfBeekeeping = i.getYearsofBeekeeping();
settingsArray.add(0, String.valueOf(settingsYearsOfBeekeeping));
settingsLocation = i.getLocation();
settingsArray.add(0, settingsLocation);
Log.e("Pay Attention", settingsArray.toString());
}
}
}
});
Log.e("Pay Attention", settingsArray.toString());
return settingsArray;
The First Log statement returns:[Littleton, 5, 4, 3, 1, 2]
The Second Log statement returns: []
I create the list earlier in the class, so it is not just local to the done method.
public static List<String> settingsArray = new ArrayList<String>();
once I get out of my method the list is empty.
That's the thing, you didn't "get out" of that method - it hasn't been entered yet.
Basically, you shouldn't return from asynchronous methods if you are trying to return the data that you're waiting on.
If you want to correctly return that list, either
Pass through new FindCallback<settings>() as a parameter to that method, and give it to findInBackground
Define your own callback interface, which can send data back from within the done method.
In both cases, you can make the method void.
For example, option 1. (I made it static because there doesn't appear to be a need for any instance of the class that contains the method)
public static void doStuff(String displayName, FindCallback<settings> callback)
ParseQuery<settings> query = ParseQuery.getQuery(settings.class);
query.whereEqualTo("Username", displayName);
query.orderByDescending("createdAt").setLimit(1);
query.findInBackground(callback);
}
And that's it.
You call it like so, from anywhere, obviously replacing ApiService with your actual class name.
private List<settings> settings;
private void setupList(List<settings> settings) {
Log.d("SETTINGS", String.valueOf(settings)); // Shouldn't be empty
this.settings = settings;
/* Use the list however you want to... */
// adapter = new ArrayAdapter(MainActivity.this, settings);
// listView.setAdapter(adapter);
}
#Override
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.some_example);
ApiService.doStuff(MainActivity.Display_Name, new FindCallback<settings>() {
public void done(List<settings> settingsList, ParseException exception) {
if (exception == null) {
...
// Update the UI here
setupList(settingList);
}
}
});
}

Realm latency between writes in the background thread and retrieving objects in the UI thread?

In my app, I am synchronizing all my data via realm transactions in the background thread. However, occasionally when I try to retrieve a recently synchronized object in the UI thread, I get a null pointer exception. I have written a routine that seems to be a fix to this small latency problem, but it feels like a "hacky" solution. Any guidance would be greatly appreciated. I have posted a simplified version of the routine below.
private void attemptToEnterActivity(){
// Retrieve the object's key.
String key = Application.getInstance().getRecentlySyncedPrimaryKey();
// Retrieve the realm object with the key.
Realm realm = Realm.getDefaultInstance();
Object object = realm.where(Object.class)
.equalTo("key", key)
.findFirst();
if (object != null) {
new NavigationController(this).activity_start(new Intent(this, Activity.class));
} else {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
attemptToEnterActivity();
}
}, 200);
}
}
Instead of guessing when the object will be fetched and stored, the suggestion is to use RealmChangeListener. See doc here for more information.
In your case, you can also use Realm's async query like:
RealmResults<Object> results = realm.where(Object.class)
.equalTo("key", key).findAllAsync();
results.addChnageListener(newRealmChangeListener<RealmResults<Object>>() {
#Override
public void onChange(RealmResults<Object> objects) {
if (objects.size() > 0) {
Object object = objects.first();
// ....
}
}
});

AsyncTask parameters and use of “…” in Java

void saveSnapshot(final SnapshotMetadata snapshotMetadata) {
AsyncTask<Void, Void, Snapshots.OpenSnapshotResult> task =
new AsyncTask<Void, Void, Snapshots.OpenSnapshotResult>() {
#Override
protected Snapshots.OpenSnapshotResult doInBackground(Void... params) {
if (snapshotMetadata == null) {
Log.i(TAG, "Calling open with " + currentSaveName);
return Games.Snapshots.open(mGoogleApiClient, currentSaveName, true)
.await();
}
else {
Log.i(TAG, "Calling open with " + snapshotMetadata);
return Games.Snapshots.open(mGoogleApiClient, snapshotMetadata)
.await();
}
}
#Override
protected void onPostExecute(Snapshots.OpenSnapshotResult result) {
Snapshot toWrite = processSnapshotOpenResult(RC_SAVE_SNAPSHOT, result, 0);
if (toWrite != null) {
Log.i(TAG, writeSnapshot(toWrite));
}
else {
Log.e(TAG, "Error opening snapshot: " + result.toString());
}
}
};
task.execute();
}
An AsyncTask object is being created I understand. I see from docs parameters can be changed or defined as needed. I could use more explanation on exactly why the first two parameters would be declared as Void, Void. As well doInBackground params type is a Void...? Is there significance to the use of "..." for instance what might be the difference between plain "Void" and "Void...".
I look forward to any responses or comments. The code I am taking from the CollectAllTheStars Google Play Games Services Basic Samples.
Thank you.
The 3 generics are used to specify what types go to the doInBackground(), onProgressUpdate() and onPostExecute() methods of the AsyncTask. This allows you to indicate what specific types of objects the AsyncTask deals with for processing (Params), uses for progress updates (Progress) and gets as a final result (Result). The reason it uses ... is due to variable arguments: you can pass more than one parameter and progress report in the APIs. Void is used as it is a proper object indicating the lack of a real object (i.e. boxing.)
Three dots (...) in Java denotes a Vararg, which means you can pass zero or more objects (as an array) into your method (or AsyncTask or whatever). They are explained really well here:
Java, 3 dots in parameters
I believe the confusing part here is that the generics define the parameter type for some methods, as well as the return type for another method at the same time. And also we never call the methods overridden by our AsyncTask directly, instead the parameters are passed through by other methods we call. It doesn't help either that a lot of examples use <Void, Void, Integer>, where the first and second type can't be distinguished.
That's why I want to throw in some commented sample code in addition to the other answers.
Note that, when ignoring varargs:
The parameter type of onPostExecute(ResultClass result) is the same as the return type of ResultClass doInBackground(BackgroundParameterClass... parameters)
The parameter type of publishProgress(ProgressClass progress) is the same as the parameter type of onProgressUpdate(ProgressClass... values)
The parameter type of execute(BackgroundParameterClass backgroundParameter); is the same as the parameter type of doInBackground(BackgroundParameterClass... params)
private static class BackgroundParameterClass {};
private static class ProgressClass {};
private static class ResultClass {};
/**
* This AsyncTask could for example download a image from a web server
*/
private static class MyAsyncTask extends AsyncTask<BackgroundParameterClass, ProgressClass, ResultClass> {
#Override
protected void onPreExecute() {
// this is called on the UI thread
// do anything you need to do before the background word start
// e.g. disable the download button
}
#Override
protected ResultClass doInBackground(BackgroundParameterClass... params) {
// Do some background work here, for example in a loop
// call then publishProgress(B... values)
// e.g download the image from a server
for (int index = 0; index < 10; index++) {
// download the image in chunks
ProgressClass progress = new ProgressClass();
publishProgress(progress);
}
ResultClass result = new ResultClass();
return result;
}
#Override
protected void onProgressUpdate(ProgressClass... values) {
// this is called on the UI thread
// e.g. update a loading bar
}
#Override
protected void onPostExecute(ResultClass resultClass) {
// this is called on the UI thread
// e.g. display the image in your UI
}
}
Then get the MyAsyncTask going by calling
new MyAsyncTask().execute(new BackgroundParameterClass());

GWT Asynchronouscallback timeout issue: Always going in OnFailure()

I am new to GWT. I have written a piece of code which makes asynchronous calls to the server. The server side code is running fine as seen through the logs. But on the client side I am getting a failure message.
I am trying to load large amount of data from the server. It seems like the async call times out before the entire data is returned from the server. Is there a way I can increase the timeout of the call? or is there any other issue with my code?
public MapDataServiceFacadeAsync getMapDataServiceInstance()
{
if (mapDataService == null)
{
mapDataService = MapDataServiceFacade.Util.getInstance();
}
return mapDataService;
public void setTreeInstance(final String productName, final Object invObject, final boolean isToLoadTickets, final SearchItem search)
{
refreshSearch = search;
this.inventoryMapPanel = (InventoryMapPanel) invObject;
long startTime = System.currentTimeMillis();
getMapDataServiceInstance().getProductTree(userProfile, isToLoadTickets, search, new AsyncCallback()
{
public void onFailure(Throwable caught)
{
CommonMapUI.loadLabel(false);
Window.alert("Failed to Load Tree. Please try again");
}
public void onSuccess(Object result)
{
tmpData = (MapItem[]) ((HashMap) result).get("tree");
if (tmpData == null && Count < 3)
{
Count++;
setTreeInstance(productName, invObject, isToLoadTickets, search);
}
else
{
buildProductTree(result, invObject, isToLoadTickets);
}
}
});
}
It is always throwing the error "Failed to load Tree" if I try and retrieve large amount of data. It works fine if small amount of data is to be loaded.
Interface:
public interface MapDataServiceFacadeAsync {
public void getProductTree(CommonUserProfile user, boolean isToLoadTickets,SearchItem search, AsyncCallback asynCall);
Any help would be appreciated.

Resources