In a loop, I need to call multiple times a method with callback . How can I know when all is finished ?
#Override
public void onObjectsMustBeParsed(String parsableObjects) {
String[] parsedObjects = parsableObjects.split(",");
for (String parsedObject : parsedObjects){
loadObject(parsedObject, new LoadObjectCallback() {
#Override
public void onObjectLoaded(Object object) {
//Object Loaded
saveObject(object, new SaveObjectCallback() {
#Override
public void onObjectSaved() {
// Object saved
}
#Override
public void onError() {
// Object not saved
}
});
}
#Override
public void onError(Throwable throwable) {
// Object not Loaded
}
});
}
}
// => do something when all processing of parsed-objects are finished
// do something if all is ok
// do other thing if partially ok
Note : To manipulate my data, I use a repository with local and remote data sources. This piece of code is a part of repository.
Add a volatile integer which indicates the amount of running tasks. Increment when you start a task. Decrement in onObjectLoaded or in onObjectSaved. Then after every decrement check if the task counter is nul.
Similar approach to the comments, but using an AtomicInteger instead:
AtomicInteger countDownLatch = null;
#Override
public void onObjectsMustBeParsed(String parsableObjects) {
String[] parsedObjects = parsableObjects.split(",");
countDownLatch = new AtomicInteger(parsedObjects.length);
for (String parsedObject : parsedObjects){
loadObject(parsedObject, new LoadObjectCallback() {
#Override
public void onObjectLoaded(Object object) {
//Object Loaded
saveObject(object, new SaveObjectCallback() {
#Override
public void onObjectSaved() {
// Object saved
int value = countDownLatch.decrementAndGet();
if ( value == 0 ) {
// we are done
}
}
#Override
public void onError() {
// Object not saved
int value = countDownLatch.decrementAndGet();
if ( value == 0 ) {
// we are done
}
}
});
}
#Override
public void onError(Throwable throwable) {
// Object not Loaded
}
});
}
}
Related
I have three different network calls to be made :
The first gets list of data from server.
On the basis of list index from the above response, app makes a another network call.
Finally the the third network call is made based on the response from above and content is set on the textview.
What I have tried:
Added the network calls in loop, But the problem is that the after the first network call, the list iterates and then is terminated while callbacks from other network calls are not made according to their sequence.
I want to have some mechanism, so that while iterating list, it should wait, and make other callbacks on sequence, and when the data is successfully sets to text fields then iterate again and do it same for all list index.. here is my code ??
Can anyone help me please
public void setDataToTextBox(String text) {
mytextbox.setText(text.toString());
}
public void getData(final int LID) {
RestAdapter adapter = new RestAdapter(this, "http://localhost:2000/api");
ResponseDemoRepository responseDemoRepository = adapter.createRepository(ResponseDemoRepository.class);
responseDemoRepository.findAll(new ListCallback < ResponseDemo > () {
#Override
public synchronized void onSuccess(List < ResponseDemo > responseDemoList) {
for (int i = 0; i < responseDemoList.size(); i++) {
if (responseDemoList.get(i).getLID() == 1) {
getnewID(responseDemoList.get(i).getTaskAssignmentID());
}
}
}
#Override
public synchronized void onError(Throwable t) {}
});
}
public void getnewID(final int TaskID) {
RestAdapter adapter = new RestAdapter(this,
"http://localhost:2000/api");
TaskAssignmentsDemoRepository taskAssignmentsDemoRepository =
adapter.createRepository(TaskAssignmentsDemoRepository.class);
taskAssignmentsDemoRepository.findById(TaskID, new ObjectCallback < TaskAssignmentsDemo > () {
#Override
public synchronized void onSuccess(TaskAssignmentsDemo object) {
getNewData(object.getData01()); // object.getData01() is int #
}
#Override
public synchronized void onError(Throwable t) {
Toast.makeText(getBaseContext(), "Error",
Toast.LENGTH_LONG).show();
}
});
}
public void getNewData(final int ID) {
RestAdapter adapter = new RestAdapter(this, "http://localhost:2000/api");
Hadith_Repository hadithRepository = adapter.createRepository(Hadith_Repository.class);
hadithRepository.findById(ID, new ObjectCallback < Hadith > () {
#Override
public synchronized void onSuccess(Hadith object) {
setDataToTextBox(object.getHadith_data());
}
}
#Override public synchronized void onError(Throwable t) {
Toast.makeText(getBaseContext(), "Error", Toast.LENGTH_LONG).show();
}
});
}
I have one case when I need to return an observable immediately, but then replace this observable with another one.
Here is an example
private Flowable<byte[]> mFlowableStream = Flowable.empty();
#Override
public Flowable<byte[]> startStreamRead() {
bindToService();
return mFlowableStream;
}
And then after binding to service I provide it a callback connection like that
#Override
public void bindToService() {
mAppContext.bindService(new Intent(mAppContext,StreamService.class), mServiceConnection, 0);
}
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
mServiceInterection = ((StreamServiceInterection.LocalBinder) binder).getServiceInteractor();
mStreamDisposable = mServiceInterection.getStream()
.subscribe(new Consumer<byte[]>() {
#Override
public void accept(byte[] data) throws Exception {
}
});
}
What I want to do is to somehow replace returned previously mFlowableStream with a new observable that I got from service.
What are possible strategies to implement this ? Maybe I should return some other value, like Future.
Please suggest how to solve this problem
Thanks
You can use Flowable.create instead of Flowable.empty
Then when new data come, just push to flowable.
Like Example
final ArrayList<FlowableEmitter<Integer>> arrEmitter = new ArrayList<>();
Flowable<Integer> futureFlow = Flowable.create(new FlowableOnSubscribe<Integer>() {
#Override
public void subscribe(final FlowableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
arrEmitter.add(e); // hold emitter to use later
}
}, BackpressureStrategy.BUFFER);
futureFlow.subscribe(new ResourceSubscriber<Integer>() {
#Override
public void onNext(Integer integer) {
System.out.println("onNext: " + integer);
}
#Override
public void onError(Throwable t) {
}
#Override
public void onComplete() {
System.out.println("onComplete");
}
});
// =========== When data come
FlowableEmitter<Integer> holdEmitter = arrEmitter.get(0);
holdEmitter.onNext(3);
Or use you can use **Subject* type according to your need
Understanding RxJava Subject — Publish, Replay, Behavior and Async Subject
Hi I just start learning Reactive programming using RxJava2.
How do I create a task that runs in the background thread and then complete on main thread using RxJava2.
Example in Android we use AsyncTask just like example below
private class MyTask extends AsyncTask<String, Integer, Boolean>
{
#Override
protected Boolean doInBackground(String... paths)
{
for (int index = 0; index < paths.length; index++)
{
boolean result = copyFileToExternal(paths[index]);
if (result == true)
{
// update UI
publishProgress(index);
}
else
{
// stop the background process
return false;
}
}
return true;
}
#Override
protected void onProgressUpdate(Integer... values)
{
super.onProgressUpdate(values);
int count = values[0];
// this will update my textview to show the number of files copied
myTextView.setText("Total files: " + count);
}
#Override
protected void onPostExecute(Boolean result)
{
super.onPostExecute(result);
if (result)
{
// display a success dialog
ShowSuccessAlertDialog();
}
else
{
// display a fail dialog
ShowFailAlertDialog();
}
}
}
For this example I want to pass in a Array / ArrayList of Strings and it is use to execute some method in the background thread. Then every success result will update my TextView (UI thread). If one of the process fail, I want it to stop directly. Lastly I want to update my Views when the process has completed.
I only manage to get this far
Observable.just(paths).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ArrayList<String>>()
{
private boolean result;
#Override
public void onSubscribe(Disposable d)
{
}
#Override
public void onNext(ArrayList<String> paths)
{
for (int index = 0; index < paths.size(); index++)
{
result = copyFileToExternal(paths[index]);
if (result == true)
{
// cant update UI because is in background thread
myTextView.setText("Total files: " + index);
}
else
{
// end the loop
break;
}
}
}
#Override
public void onError(Throwable e)
{
}
#Override
public void onComplete()
{
if (result)
{
// cant display because it is still in background thread
ShowSuccessAlertDialog();
}
else
{
// cant display because it is still in background thread
ShowFailAlertDialog();
}
}
});
I looked at a few tutorials but can't seem to find the answer.
Thanks in advance for the help
I would do something like this:
Observable.fromArray(getPaths())
.map(path -> copyFileToExternal(path))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aInteger -> Log.i("test", "update UI"),
throwable -> ShowFailAlertDialog),
() -> ShowSuccessAlertDialog());
A good idea is usually to have a "handler" for controlling the subscription to your observer. So that, when you need to stop your background task (for example because the user left the Activity), you can use it. For this purpose you can use subscribeWith instead of subscribe, that receive as input a ResourceObserver: in this way you get a Disposable.
Disposable subscription = Observable.fromArray(getPaths())
.map(path -> copyFileToExternal(path))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new ResourceObserver<Integer>() {
#Override
public void onNext(#NonNull Integer index) {
Log.i("test", "update UI");
}
#Override
public void onError(#NonNull Throwable e) {
ShowFailAlertDialog();
}
#Override
public void onComplete() {
ShowSuccessAlertDialog();
}
});
When you need to stop the task you can just call:
subscription.dispose();
I'm new at this, but I got a working example..
//Observable
Observable.just("input_parameter")
.subscribeOn(Schedulers.io())//creation of secondary thread
.map(new Function<String, String>() {//<input obj,return obj>
#Override
public String apply(String cad){//input obj
Log.d(TAG,"thread :"+Thread.currentThread().getName());
//runs in a secondary thread
return "result text: "+doLongNetworkOperation();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(MyObserver);//now this runs in main thread
And MyObserver:
//Observer
Observer MyObserver = new Observer() {
#Override
public void onSubscribe(Disposable d) {
Log.d(TAG,"onSubscribe thread:"+Thread.currentThread().getName());
}
#Override
public void onNext(Object value) {
Log.d(TAG,"on next, valor:<<"+value.toString()+">> \n nombre hilo:"+Thread.currentThread().getName());
}
#Override
public void onError(Throwable e) {
Log.d(TAG,"error "+e.toString());
}
#Override
public void onComplete() {
Log.d(TAG,"onCompleted thread:"+Thread.currentThread().getName());
}
};
Plz, let me know if this works for you.
In a loop, I need to call multiple times a method with callback. How can i use parameter parsedObject in onObjectChecked() ?
#Override
public void onObjectsMustBeParsed(String parsableObjects) {
String[] parsedObjects = parsableObjects.split(",");
for (String parsedObject : parsedObjects){
checkObject(parsedObject, new CheckObjectCallback() {
#Override
public void onObjectChecked() {
//Object check
// here call method with parameters : parsedObject
// Example : transformObject(parsedObject);
}
#Override
public void onError() {
// Object not checked
}
});
}
}
Note : When I don't have a loop, I use a final variable. I don't know if it's a good practice ! Please tell me if it is !
If you have control over this part of the code you should instead change your architecture and have the parsedObject supplied as parameter to onObjectChecked().
But to have only a few changes to your current code you could just implement a simple inner class (not anonymous) holding the parsedObject.
#Override
public void onObjectsMustBeParsed(String parsableObjects) {
String[] parsedObjects = parsableObjects.split(",");
MyCheckObjectCallback callback = new MyCheckObjectCallback();
for (String parsedObject : parsedObjects) {
callback.parsedObject = parsedObject;
checkObject(parsedObject, callback);
}
}
private class MyCheckObjectCallback implements CheckObjectCallback {
String parsedObject = null;
#Override
public void onObjectChecked() {
// Object check
// here call method with parameters : parsedObject
// Example : transformObject(parsedObject);
}
#Override
public void onError() {
// Object not checked
}
}
i'm new in Rx programming (and I'm having a lot of fun so far ^^).
I'm trying to transform a AsyncTask call into an Rx function.
My function :
Get all the installed apps
normalize the labels
sort everything alphabetically
arrange them by group of letter (it was a Multimap(letter, list of apps)) and pass the result to an adapter to display everything.
Here is how I'm doing so far with Rx :
Observable.from(getInstalledApps(getActivity(), false))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.map(new Func1<ResolvedActivityInfoWrapper, ResolvedActivityInfoWrapper>() {
#Override
public ResolvedActivityInfoWrapper call(ResolvedActivityInfoWrapper act) {
// Normalize labels
act.setLabel(Normalizer.normalize(act.getLabel(getPackageManager()).replace(String.valueOf((char) 160), "").trim(), Normalizer.Form.NFD).replaceAll("\\p{M}", ""));
return act;
}
})
.toList()
.subscribe(new Observer<List<ResolvedActivityInfoWrapper>>() {
List<ResolvedActivityInfoWrapper> list;
#Override
public void onCompleted() {
Observable.from(list).groupBy(new Func1<ResolvedActivityInfoWrapper, String>() {
#Override
public String call(ResolvedActivityInfoWrapper input) {
//Get groups by letter
String label = input.getLabel(getPackageManager());
if (!TextUtils.isEmpty(label)) {
String firstChar = label.substring(0, 1);
if (pattern.matcher(firstChar).matches()) {
return firstChar.toUpperCase();
}
}
return "#";
}
}).subscribe(this); // implementation below
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<ResolvedActivityInfoWrapper> list) {
Collections.sort(list, new Comparator<ActivityInfoWrapper>() {
#Override
// Sort all the apps in the list, not sure it's a good way to do it
public int compare(ActivityInfoWrapper info1, ActivityInfoWrapper info2) {
return info1.getLabel(getPackageManager()).compareToIgnoreCase(info2.getLabel(getPackageManager()));
}
});
this.list = list;
}
});
Once I groupedBy letters, on complete I subscribe with this :
#Override
public void onCompleted() {
//display the apps
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(GroupedObservable<String, ResolvedActivityInfoWrapper> input) {
//For each list of apps by letter i subscribe with an observer that will handle those apps (observer code below)
input.subscribe(new TestObserver(input.getKey()));
}
Observer :
private class TestObserver implements Observer<ResolvedActivityInfoWrapper> {
List<ResolvedActivityInfoWrapper> list;
String letter;
public TestObserver(String letter) {
list = new ArrayList<>();
this.letter = letter;
}
#Override
public void onCompleted() {
adapter.addData(letter, list);
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(ResolvedActivityInfoWrapper input) {
list.add(input);
}
}
Everything works correctly excpets for one problem : the observer's onCompleted are called not in the right order. So I got all my apps, sorted by letter, but the groups are nots displayed in the right order (C first, then Y, then M etc ...).
I guess there are plenty of errors in the code, can you help me with this probleme and maybe understanding how all this works please ?
Thanks
UPDATE :
Following the advices in the commentary section (thanks people), here is what I'm trying after normalizing the labels :
Observable.from(list).groupBy(new Func1<ResolvedActivityInfoWrapper, String>() {
#Override
public String call(ResolvedActivityInfoWrapper input) {
String label = input.getLabel(getPackageManager());
if (!TextUtils.isEmpty(label)) {
String firstChar = label.substring(0, 1);
if (pattern.matcher(firstChar).matches()) {
return firstChar.toUpperCase();
}
}
return "#";
}
})
.toSortedList(new Func2<GroupedObservable<String, ResolvedActivityInfoWrapper>, GroupedObservable<String, ResolvedActivityInfoWrapper>, Integer>() {
#Override
public Integer call(GroupedObservable<String, ResolvedActivityInfoWrapper> obs1, GroupedObservable<String, ResolvedActivityInfoWrapper> obs2) {
return obs1.getKey().compareToIgnoreCase(obs2.getKey());
}
})
.subscribe(new Observer<List<GroupedObservable<String, ResolvedActivityInfoWrapper>>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<GroupedObservable<String, ResolvedActivityInfoWrapper>> input) {
String test = input.get(0).getKey();
}
});
But it never goes into the Compare function.