WebSocket and Rx Java - android

I'm develop an android app that communicates with the server using a protocol WebSocket. I use AsyncAndroid lib. WebSocket has listener, that receive data from server.
Something like this
private WebSocket.StringCallback mStringCallback = new WebSocket.StringCallback() {
#Override
public void onStringAvailable(String s) {
}
};
I need write api this, and i want use rxjava. But i cannot imagine, that should be Observable, and that Observer. i tried to do Observable string received from server into WebSocket listener, but i think it is bad idea.
Are there any ideas how correctly build api.
Thank u.

You could wrap WebSocket into a new interface like this:
interface RxWebSocket {
void send(byte[]); // send data
Observable<String> stringObservable(); // receive string data
}
Then in a RxWebSocket implementation you can use PublishSubject with an internal WebSocket.StringCallback to publish the Strings.

Related

Bidirectional-streaming in Android causing OOMs

I've set up a bidirectional stream construct in an Android app, where I am currently using the mechanism to send chunks of large files. The problem I am having is that my app will receive a request message for a file, then I'll respond with potentially hundreds of MBs worth of response GRPC messages, frequently causing an OOM. Pseudo code:
public class Myclass implements StreamObserver<CameraRequest>, Closeable {
...
public void onNext(Request req) {
for (Chunk chunk : getChunks(req))
this.requestObserver.onNext(builder.setChunk(chunk).build());
}
...
}
Is there some good way to rate limit the number of outstanding calls to onNext based on what has actually been put on the wire (and corresponding memory made freeable)? IE only allowing 10 calls to onNext to be made, then subsequent ones block until the data for the preceding calls has successfully been sent by the underlying protocol stack? I could implement a full e2e acknowledgement window in my wire protocol TCP style, but was hoping there was an easier/built in technique others were using.
Thanks!
Cast requestObserver to ClientCallStreamObserver. You can then call clientCallStreamObserver.isReady() to check if you should stop sending.
You will then need notifications for when the RPC is ready for more messages, to resume sending. For that, implement ClientResponseObserver and call clientCallStreamObserver.setOnReadyHandler(Runnable) within beforeStart().
Putting that all together, gets you something like:
public class MyClass implements
ClientResponseObserver<CameraRequest,CameraResponse> {
private ClientCallStreamObserver<CameraRequest> requestObserver;
private Iterable<Chunk> chunks;
public void beforeStart(ClientCallStreamObserver<CameraRequest> requestObserver) {
this.requestObserver = requestObserver;
requestObserver.setOnReadyHandler(MyClass::drain);
}
public void onNext(CameraRequest req) {
// I don't know if this assert valid for your protocol
assert chunks == null || !chunks.hasNext();
chunks = getChunks(req);
drain();
}
public void drain() {
while (requestObserver.isReady() && chunks.hasNext()) {
Chunk chunk = chunks.next();
requestObserver.onNext(builder.setChunk(chunk).build());
}
}
...
}
You can check out the flow control example here.

Does RxJava Observable actually observe Retrofit so if I receive data then it will automatically make another exact same call?

So I'm trying to make a messaging part working where a Retrofit API returns a list of messages for a conversation. Sure, the conversation refreshes each time the user chooses to refresh the Activity.
But say the recipient sends me a message, will RxJava Observable automatically make this exact same API call to Retrofit and retrieve the updated data?
If not then what's an easy way I can achieve that?
getApi().getConversationMessagesQuery(request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe((Response<GetConversationDetailsQuery> response) -> {
if (response.body() != null) {
List<Message> messages = response.body().getMessages();
RecyclerView.Adapter adapter = getAdapter();
if (adapter instanceof MessageListAdapter) {
((MessageListAdapter) adapter).setItems(messages, firstLoading);
} else {
adapter = MessageListAdapter.getInstance(messages, firstLoading);
setAdapter(adapter);
}
}
}, (Throwable ex) -> {
}
));
Does the RxJava Observable automatically makes this exact same API call to Retrofit and retrieves the updated data
No, RxJava cannot do that automatically for you.
what's an easy way I can manage to do that?
With simple REST API calls there is no way to detect that the data has changed. You would have to implement some Websocket based technology on your server to achieve this.

How to use RxJava to wait the end of two lists of Retrofit requests

Let me describe my situation:
I want to register new records via an API.
I want to update some records via an API.
I need to be notified when all of these requests have finished, to start another task.
Specifically I have two ArrayList:
ArrayList<Report> createdReports = myHelper.getOfflineCreatedReports();
ArrayList<Report> editedReports = myHelper.getOfflineEditedReports();
Each report can use methods to get Observable instances from my ApiService (Retrofit implementation).
Observable<NewReportResponse> createdReportsObs = Observable.from(createdReports) // .just() != .from()
.flatMap(new Func1<Report, Observable<NewReportResponse>>() {
#Override
public Observable<NewReportResponse> call(Report report) {
return report.postToServer();
}
});
Observable<NewReportResponse> editedReportsObs = Observable.from(editedReports)
.flatMap(new Func1<Report, Observable<NewReportResponse>>() {
#Override
public Observable<NewReportResponse> call(Report report) {
return report.updateInServer();
}
});
I am using the flatMap operator to get one Observable for each report.
But I am not sure how to wait until all of the requests have finished.
I was thinking in using the zip operator.
Observable.zip(createdReportsObs, editedReportsObs, new Func2<NewReportResponse, NewReportResponse, Boolean>() {
#Override
public Boolean call(NewReportResponse justOneResponse, NewReportResponse justOneResponse2) {
return false;
}
});
Unfortunately I saw some examples where zip is used to create pairs of Observables.
Please suggest me what operator I can use to achieve it. Or how to do it using rxJava with a different approach.
Thank you in advance.
Are you using RxJava 2? If so you can use the new completable api. This is assuming you don't need to know any of the server results, just need to wait for them to complete.
Completeable.merge(createdReportsObs.toCompleteable(),
editedReportsObs.toCompleteable())
.subscribe()
This is my way. May not best practice.
Observable.merge(createdReportsObs, editedReportsObs)
.toList()
.flatMap(Observable::from)
.xxx //Now they are completed, do what you want
.subscribe();

Is it possible to send a synchronous request in the Firebase?

I'm using Firebase Android SDK and became interested in sending synchronous request instead of asynchronous. According to the documentation, in any request callbacks are presented. But what about the synchronicity?
Thanks!
There is no way to synchronously load data from the Firebase Database.
While it is common for developers new to Firebase to wish for a synchronous method, it simply doesn't fit with Firebase's data synchronization model. Also see my answer here: Setting Singleton property value in Firebase Listener
It is not possible to load data synchronously with the official SDK. However, you can access all the data in firebase using the REST API. This would allow you to make synchronous calls. As mentioned about, Firebase is a realtime database and you will be missing the feature of updates when your data changes.
I made a simple class to call tasks synchronously in Android.
Note that this is similar to Javascript's async await function.
Check my gist.
TasksManager.class
public class TasksManager {
...
public ExecutorService getExecutor() {
if (mDefaultExecutor == null || mDefaultExecutor.isShutdown() || mDefaultExecutor.isTerminated()) {
// Create a new ThreadPoolExecutor with 2 threads for each processor on the
// device and a 60 second keep-alive time.
int numCores = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor executor = new ThreadPoolExecutor(
numCores * 2,
numCores * 2,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>()
);
mDefaultExecutor = executor;
}
return mDefaultExecutor;
}
public static <TResult> Task<TResult> call(#NonNull Callable<TResult> callable) {
return Tasks.call(getInstance().getExecutor(), callable);
}
}
Here's a sample code to use it.
TasksManager.call(() -> {
Tasks.await(AuthManager.signInAnonymously());
// You can use multiple Tasks.await method here.
// Tasks.await(getUserTask());
// Tasks.await(getProfileTask());
// Tasks.await(moreAwesomeTask());
// ...
startMainActivity();
return null;
}).addOnFailureListener(e -> {
Log.w(TAG, "signInAnonymously:ERROR", e);
});
While it is not possible to load data from the FirebaseDatabase in a synchronous way, it is possible to wait for the load to finish synchronously.
You can wrap your value listener in a CountDownLatch and count down,
once the onDataChange or onCancelled implementation is called.
This is actually what the Tasks api is doing internally if you call Tasks.await(someTask).
You should use the value listener for single event listening, because in this case I assume you don't want continued updates. And use a proper timeout for the CountDownLatch, since Firebase won't timeout, ever.
reference.addListenerForSingleValueEvent(...);
You also have to take into account, that if you have the FirebaseDatabase
cache enabled, the first result might not be the actual value on the
server.
I have to add: While this might work, it is against the idea how firebase is designed and supposed to be used, as Frank already said.
If you are using Kotlin, add an extension function:
private suspend fun <TResult> Task<TResult>.await(): TResult? {
return try {
Tasks.await(this)
} catch (e: Exception) {
null
}
}
Now you can do
val snapshot = fireStore.collection(USER_ROOT_PATH).document(documentPath)?.get()?.await()

Particular overload of Azure Mobile Service invokeApi is not working while calling custom API

Where is the documentation/sample for all overloads of invokeApi function for Azure Mobile Service client SDK for Android?
I found this article and tried following code, which does not work. There are no compile time or run time errors, invokeApi gets called, but it does not come back to onSuccess or onFailure. If I call invokeApi without order object, everything works as expected
PizzaOrder order = new PizzaOrder();
order.Size = "Large";
order.Flavor = "Four cheeses";
order.UserPhone = "555-555-1234";
ListenableFuture<PizzaOrderResponse> testresult = mClient.invokeApi("bookservice", order, PizzaOrderResponse.class);
Futures.addCallback(testresult, new FutureCallback<PizzaOrderResponse>() {
#Override
public void onFailure(Throwable exc) {
// failure handling code here
}
#Override
public void onSuccess(PizzaOrderResponse testresult) {
// success handling code here
}
});
One of the properties in the data object being returned by the custom API had incorrect data type. I am still not sure where the good documentation is and why custom API call did not fail but at least it is working now.

Categories

Resources