RxJava2 how to observe UDP packets? - android

I am just getting started with RxJava2 and wonder how I could correctly implement a UDP observable.
I already have some working code, but I think there may be some issues: see the 4 questions in the comments of the source-code below.
I've also published the code on GitHub RxJava2_Udp: comments, issues and pull requests welcome.
class UdpObservable {
private static class UdpThread extends Thread {
private final int portNo;
private final int bufferSizeInBytes;
private final ObservableEmitter<DatagramPacket> emitter;
private DatagramSocket udpSocket;
private UdpThread(#NonNull ObservableEmitter<DatagramPacket> emitter
, int portNo, int bufferSizeInBytes) {
this.emitter = emitter;
this.portNo = portNo;
this.bufferSizeInBytes = bufferSizeInBytes;
}
#Override
public void run() {
try {
// we don't want to create the DatagramSocket in the constructor, because this
// might raise an Exception that the observer wants to handle
udpSocket = new DatagramSocket(portNo);
try {
/* QUESTION 1:
Do I really need to check isInterrupted() and emitter.isDisposed()?
When the thread is interrupted an interrupted exception will
be raised anyway and the emitter is being disposed (this is what
caused the interruption)
*/
while (!isInterrupted() && !emitter.isDisposed()) {
byte[] rcvBuffer = new byte[bufferSizeInBytes];
DatagramPacket datagramPacket = new DatagramPacket(rcvBuffer, rcvBuffer.length);
udpSocket.receive(datagramPacket);
// QUESTION 1a: same as QUESTION 1 above
if (!isInterrupted() && !emitter.isDisposed()) {
emitter.onNext(datagramPacket);
}
}
} finally {
closeUdpSocket();
}
} catch (Throwable th) {
// the thread will only be interrupted when the observer has unsubscribed:
// so we need not report it
if (!isInterrupted()) {
if (!emitter.isDisposed()) {
emitter.onError(th);
} else {
// QUESTION 2: is this the correct way to handle errors, when the emitter
// is already disposed?
RxJavaPlugins.onError(th);
}
}
}
}
private void closeUdpSocket() {
if (!udpSocket.isClosed()) {
udpSocket.close();
}
}
#Override
public void interrupt() {
super.interrupt();
// QUESTION 3: this is called from an external thread, right, so
// how can we correctly synchronize the access to udpSocket?
closeUdpSocket();
}
}
/**
* creates an Observable that will emit all UDP datagrams of a UDP port.
* <p>
* This will be an infinite stream that ends when the observer unsubscribes, or when an error
* occurs. The observer does not handle backpressure.
* </p>
*/
public static Observable<DatagramPacket> create(final int portNo, final int bufferSizeInBytes) {
return Observable.create(
new ObservableOnSubscribe<DatagramPacket>() {
#Override
public void subscribe(ObservableEmitter<DatagramPacket> emitter) throws Exception {
final UdpThread udpThread = new UdpThread(emitter, portNo, bufferSizeInBytes);
/* QUESTION 4: Is this the right way to handle unsubscription?
*/
emitter.setCancellable(new Cancellable() {
#Override
public void cancel() throws Exception {
udpThread.interrupt();
}
});
udpThread.start();
}
}
);
}
}

Generally speaking, I think it is not the right way of creating it, you should not create thread yourself, as RxJava and it's Schedulers should do it for you.
Consider that the code that code executed at the ObservableOnSubscribe will run at a thread per your Scheduler strategy, so you don't need to construct it yourself. just do the ude while-loop inside the create.
You don't need to call Thread.interrupt() method, RxJava will do that for you when you're dispose (unsubscribe) the Observable. (set the cancelable before the while loop of course)
As for your questions:
You don't need to check for the interrupted as the exception will
be raise if you'r waiting for io operation, you also don't need to
check for the disposal because onNext() will do it for you and will
not emit of unsubscribed.
Again you can call onError and the emitter will take care of checking if the Observable was unsubscribed.
As said before, there should be no Thread, but for resource cleanup, you can use the emitter.setCancellable method. (close the stream), this is happen on the same thread your code runs.
Answered before, Thread.interrput() will be raised with dispose/unsubscribe by RxJava, resource clean up should go to the emitter.setCancellable method

Related

How to wait for async APIs in Android?

In android, there are many async APIs such as WebView's evaluateJavascript, which will Asynchronously evaluates JavaScript in the context of the currently displayed page. Usually an execution will just proceed to the successive statements after the call of an async API without any waiting.
But how can I wait until this call finishes its executing, before proceeding to the successive statements. For example,
webview.evaluateJavascript("JS code", new ValueCallback<String> {
public void onReceiveValue(String value) {
//get JS return here
}
});
//Remaining code
How can I make sure the remaining code is executed after webview.evaluateJavascript has finished its executing (i.e., its callback onReceiveValue has finished its executing).
Edit: To be more precise, what I want is that remaining code should be executed after onReceiveValue has finished executing.
I find out a workaround by using JavaScript interface. The idea is that we create a bridge class that contains a method that takes the javascript execution result as input. Then we can obtain the result at the Java end. This method works because bridge methods are invoked by JavaScript code, which is run on another thread. We only need to wait on the UI thread for a little milliseconds, then the result is here for you. The following code is an illustration:
class Bridge {
public String result = null;
#JavascriptInterface
public void putJsResult(String result) {
this.result = result;
}
public String getJsResult() {
return this.result;
}
}
Bridge bridge = new Bridge();
wv.addJavascriptInterface(bridge, "bridge");
webview.evaluateJavascript("bridge.putJsResult(func())", null);
Thread.sleep(100);
//Result is there
String result = bridge.getJsResult();
When you have to wait for code execution, a simple class to use is CountDownLatch.
An example for your problem can be:
public class AboutActivity extends Activity {
private volatile CountDownLatch jsLatch = new CountDownLatch(1);
private volatile String jsReceivedValue = null
initWebView() {
// webview init
...
webview.evaluateJavascript("JS code", new ValueCallback<String> {
public void onReceiveValue(String value) {
//get JS return here
jsReceivedValue = value
jsLatch.countDown();
}
});
try {
// wait 60 seconds or assume there was some problem during the loading
jsLatch.await(60, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// thread interrupted or time elapsed
}
if (jsReceivedValue == null) {
// show "problem during loading"
} else {
//Remaining code
}
}
}
Note that waiting for code execution on main thread, can lead to unresponsive app.
You can show a loading spinner while using a simple thread to avoid this:
new Thread(new Runnable() {
#Override
public void run() {
initWebView();
}
}).start();

Android RxJava Thread Reusal, Is it a bad practice?

I am using retrofit and Rxjava to handle api calls for my mvvm android application. Based on some tutorial, i am currently using RxJava like this.
ViewModel.java
CompositeDisposable disposable = new CompositeDisposable();
private void fetchTodolist(){
loading.setValue(true);
disposable.add(
service.getToDoList("A1833")
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableSingleObserver<ApiResponse<ArrayList<TodoItem>>>() {
#Override
public void onSuccess(ApiResponse<ArrayList<TodoItem>> value) {
if(value.getStatus() == 200){
//on call success code
} else {
//on call rejected code
}
}
#Override
public void onError(Throwable e) {
// on call error code
}
})
);
}
And now i want to cache the result of the api call on successful call into room database. So i need to use another async method and tried to reuse the new thread i created before. And here's the code.
private void fetchTodolist(){
loading.setValue(true);
Scheduler a = Schedulers.newThread();
disposable.add(
service.getToDoList("A1833")
.subscribeOn(a)
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableSingleObserver<ApiResponse<ArrayList<TodoItem>>>() {
#Override
public void onSuccess(ApiResponse<ArrayList<TodoItem>> value) {
if(value.getStatus() == 200){
a.scheduleDirect(new Runnable() {
#Override
public void run() {
long inserted = dao.insert(value);
}
});
} else {
//on call rejected code
}
}
#Override
public void onError(Throwable e) {
// on call error code
}
})
);
}
I wonder if it is a bad practice and will lead to a serious problem. And if so, what's the alternative.
Schedulers uses cached references thus newThread() returns the same Scheduler instance.
Schedulers.newThread() == Schedulers.newThread()
Generally you should avoid using newThread because it creates a new thread for every application of the operator. So if you run the sequence multiple times, new worker threads are created and dismissed without any kind of reuse. This is especially true for newThread().scheduleDirect which will start a new thread just for that single runnable and stop it afterwards.
It is recommended you use Schedulers.io() for IO operations so that those underlying worker threads are reused as much as possible later.

Serialized incoming aidl calls in one Thread

I have an App (Client) that performs remote calls using AIDL to a second App (Server). Each call to through the Binder is executed in the Server app in a different thread (TID) as designed by AIDL solution.
Is it possible to make all calls executed in the Server app be executed in just one thread? We have control over all callers (Client apps) and they will perform call in a serial mode and we don't need Server app perform the calls in a multithread way.
So, if the Client App 1 performs a remote call to a method that takes 30 seconds and before it, a second Client App 2 performs a call to the same method (or even other method) we want this second call be executed in the same Thread of the first call.
Messenger is not an option for now.
=== Updated ====
Message is not an option (for now). Here more details: We have a service with 2 type of binders: a) TransacionManager (tm) and DAOImpl (dao).
We first do a call to tm.begin() in the client and even its processed synchronously, on the Service side its is executed in a thread from Thread Pool (android aidl code). This thread TID #1 performs the begin transaction command in SQLite database.
Then we do a call to dao.selectNextId() - synchronously - and in the Service it is executed in the TID #2. In the selectNextId() method we check if the database is inTransaction and it returns false.
To confirm that the threads was the problem, we put everything in a single call to another binder (allDAO). So when we call allDAO.do() it runs on the Service side in another thread TID #3 and performs begin transc and insert very well.
Not sure if the problem is SQLite that manage different threads as separated requests (how to deal with)... We just want the Service (using aidl) perform every call from any clients in a same single thread everytime.
I was working with Mario on this issue and using the #pskink's code snippet we solved the multithreading issue.
The issue was solved redirecting all aidl calls to the main thread. To do this, we used a Handler thats receives the MainLooper and a Runnable that extends CountDownLatch.
The code of our solution bellow:
// SyncHandler.class
public class SyncHandler {
private SyncRunnable mRunnable;
public SyncHandler() {
super();
}
public SyncHandler start(#NonNull SyncRunnable runnable) {
mRunnable = runnable;
final Looper looper = Looper.getMainLooper();
Handler handler = new Handler(looper);
handler.post(mRunnable);
try {
mRunnable.await();
} catch (InterruptedException e) {
Log.e(this, "Error when SyncHandler was awaiting.", e);
}
return this;
}
public static class ReturnValue<T> {
public T value;
}
}
// SyncRunnable.class
public final class SyncRunnable extends CountDownLatch implements Runnable {
private Runnable mRunnable;
public static SyncRunnable create(Runnable runnable) {
return new SyncRunnable(runnable);
}
private SyncRunnable(Runnable runnable) {
super(1);
mRunnable = runnable;
}
#Override
public void run() {
Log.d(this, "SyncRunnable.run() executed on thread: " + Thread.currentThread());
mRunnable.run();
countDown();
}
}
//And the database call:
// TransactionManager.class
public synchronized void begin(final int ownerHashCode, String ownerName) throws RemoteException {
SyncHandler handler = new SyncHandler().start(SyncRunnable.create(new Runnable() {
#Override
public void run() {
if (mOwner == null) {
mOwner = ownerHashCode;
for (Database database : mDatabases) {
database.beginTransaction();
}
} else if (mOwner == ownerHashCode) {
throw new DbTransactionException("Error: TransactionOwner == owner");
}
}
}));
}
// DaoHelper.class
public synchronized long insert(Dao dao) {
final SyncHandler.ReturnValue<Long> value = new SyncHandler.ReturnValue<>();
SyncHandler handler = new SyncHandler().start(SyncRunnable.create(new Runnable() {
#Override
public void run() {
Log.d(DaoHelper.this, "db.inTransaction: " + mManagerDb.getDatabase().inTransaction());
value.value = mManagerDb.getDatabase().insert(mTable, null, mContentValues);
}
}));
return value.value;
}

Lazy fetching of paginated objects using RxJava

I'm almost sold to RxJava, which is a perfect companion to Retrofit, but I'm struggling into a common pattern while migrating my code: to save bandwidth, I'd like to lazily fetch (paginated) objects from my webservice as needed, while my listview (or recyclerview) is scrolling using reactive programming.
My previous code was doing the job perfectly, but reactive programming seems worth the try.
Listening to listview/recyclerview scrolling (and other boring stuffs) isn't the concern and getting an Observable is easy using Retrofit:
#GET("/api/messages")
Observable<List<Message>> getMessages(#Path("offset") int offset, #Path("limit") int limit);
I just can't figure out the pattern to use in reactive programming.
The Concat operator seems a good starting point, along with ConnectableObservable at some point to defer emission and maybe flatMap, but how ?
EDIT:
Here's my current (naive) solution:
public interface Paged<T> {
boolean isLoading();
void cancel();
void next(int count);
void next(int count, Scheduler scheduler);
Observable<List<T>> asObservable();
boolean hasCompleted();
int position();
}
And my implementation using a subject:
public abstract class SimplePaged<T> implements Paged<T> {
final PublishSubject<List<T>> subject = PublishSubject.create();
private volatile boolean loading;
private volatile int offset;
private Subscription subscription;
#Override
public boolean isLoading() {
return loading;
}
#Override
public synchronized void cancel() {
if(subscription != null && !subscription.isUnsubscribed())
subscription.unsubscribe();
if(!hasCompleted())
subject.onCompleted();
subscription = null;
loading = false;
}
#Override
public void next(int count) {
next(count, null);
}
#Override
public synchronized void next(int count, Scheduler scheduler) {
if (isLoading())
throw new IllegalStateException("you can't call next() before onNext()");
if(hasCompleted())
throw new IllegalStateException("you can't call next() after onCompleted()");
loading = true;
Observable<List<T>> obs = onNextPage(offset, count).single();
if(scheduler != null)
obs = obs.subscribeOn(scheduler); // BEWARE! onNext/onError/onComplete will happens on that scheduler!
subscription = obs.subscribe(this::onNext, this::onError, this::onComplete);
}
#Override
public Observable<List<T>> asObservable() {
return subject.asObservable();
}
#Override
public boolean hasCompleted() {
return subject.hasCompleted();
}
#Override
public int position() {
return offset;
}
/* Warning: functions below may be called from another thread */
protected synchronized void onNext(List<T> items) {
if (items != null)
offset += items.size();
loading = false;
if (items == null || items.size() == 0)
subject.onCompleted();
else
subject.onNext(items);
}
protected synchronized void onError(Throwable t) {
loading = false;
subject.onError(t);
}
protected synchronized void onComplete() {
loading = false;
}
abstract protected Observable<List<T>> onNextPage(int offset, int count);
}
Here's one out of a few potential ways to handle reactive paging. Let's assume we have a method getNextPageTrigger which returns an Observable emits some event object when the scroll listener (or whatever input) wants a new page to be loaded. In real life it would probably have the debounce operator, but in addition to that we'll make sure we only trigger it after the latest page has loaded.
We also define a method to unwrap the messages from their list:
Observable<Message> getPage(final int page) {
return service.getMessages(page * PAGE_SIZE, PAGE_SIZE)
.flatMap(messageList -> Observable.from(messageList));
}
Then we can make the actual fetching logic:
// Start with the first page.
getPage(0)
// Add on each incremental future page.
.concatWith(Observable.range(1, Integer.MAX_VALUE)
// Uses a little trick to get the next page to wait for a signal to load.
// By ignoring all actual elements emitted and casting, the trigger must
// complete before the actual page request will be made.
.concatMap(page -> getNextPageTrigger().limit(1)
.ignoreElements()
.cast(Message.class)
.concatWith(getPage(page))) // Then subscribe, etc..
This is still missing a couple potentially important things:
1 - This obviously doesn't know when to stop fetching additional pages, which means once it hits the end, depending on what the server returns, it could either keep hitting errors or empty results every time scroll is triggered. Approaches to solving this depend on how you signal to the client that there are no more pages to load.
2 - If you need error retries, I would suggest looking into the retryWhen operator. Otherwise, common network errors could cause an error in a page load to propagate.

Guidance on using a SynchronousQueue

I need to perform a series of http requests, each of which may depend on a previous http response. I have been able to achieve this using an AsyncTask "tree" of sorts, but as the decision tree grows, the AsyncTask technique grows more unwieldy.
I think that somehow using a SynchronousQueue (or other type of queue) is the best approach, but I can't seem to find any good guidance or tutorials on how to use a Queue for something like http requests.
Can anyone provide any guidance or point to any good tutorials on using SynchronousQueue or suggest the best kind of Queue?
Use a java.util.concurrent.SingleThreadExecutor and make a Runnable out of each HTTP operation and result-handler. You can submit subsequent tasks to it as you determine whether you need to continue progress.
For example, the HTTP "task" would run and submit the Result "task" on success, or the Error "task" on failure. The Result task would in-turn submit another HTTP task when it was done processing. Using SingleThreadExecutor ensures only one task runs at-a-time.
You could use a ThreadPoolExecutor if you can handle multiple operations in-flight at once.
Take all that, and wrap it in an AsyncTask that manages the top-level "kick-off" and waits for everything to complete. It would probably be useful to have a ConditionVariable or something to synchronize the "end" signal (using a Done "task") so you can safely tear down the Executor.
A SynchronousQueue doesn't do anything helpful for you here, because it leaves you to do all the tread management. If you use an Executor that is all handled and all you deal with is Runnables and Futures. That's probably why you are not finding any tutorials. Anyway, the Executors all use one of those queue implementations underneath!
As requested, here is some skeleton Java code. Unsupported untested as-is. This should get you started. You can use a different synchronization object if you don't like ConditionVariable.
This is a generic technique, not specific to Android, feel free to use it in other contexts.
This functions as a State Machine, with HttpTask et al forming the states, and the transitions are hard-coded by submitting the Next State to the ExecutorService. There's even a "Big Bang at the end, so everyone knows when to clap" in the form of the ConditionVariable.
Some may consider DoneTask and FailedTask overkill, but it keeps the Next State mechanism consistent, and lets Future<? extends ResultTask> function as a somewhat type-safe container for the results, and certainly keeps you from mis-assigning to it.
abstract class BasicTask {
final ExecutorService es;
final ConditionVariable cv;
public BasicTask(ExecutorService es, ConditionVariable cv) {
this.es = es;
this.cv = cv;
}
}
abstract class HttpTask extends BasicTask {
// source omitted.
// you should make a class to prepare e.g. Apache HTTP resources for specific tasks (see below).
}
abstract class ResultTask implements Runnable {
final ConditionVariable cv;
public ResultTask(ConditionVariable cv) {
this.cv = cv;
}
public void run() {
cv.open();
}
}
final class FailedTask extends ResultTask {
final Exception ex;
public FailedTask(ConditionVariable cv, Exception ex) {
super(cv);
this.ex = ex;
}
public Exception getError() { return ex; }
}
final class DoneTask<T> extends ResultTask {
final T results;
public DoneTask(ConditionVariable cv, T results) {
super(cv);
this.results = results;
}
public T getResults() { return results; }
}
class HttpSequence extends AsyncTask<Void,Void,Object> {
// this will capture the ending task
Future<? extends ResultTask> result;
// this is an inner class, in order to set Result. Refactor so these are small.
// if you don't like inner classes, you still need to arrange for capturing the "answer"
final class SomeHttpTask extends HttpTask implements Runnable {
public void run() {
try {
final SomeType thisStep = doTheStuff(lastStep);
if(thisStep.isDone()) {
// we are done here
result = es.submit(new DoneTask<SomeType>(cv, thisStep));
}
else if(thisStep.isFailed()) {
// not done: we can't proceed because of something in the response
throw thisStep.getError();
}
else {
// not done, everything is ok for next step
es.submit(new NextHttpTask(es, cv, thisStep));
}
}
catch(Exception ex) {
result = es.submit(new FailedTask(cv, ex));
}
}
}
final class TheFirstTask extends HttpTask implements Runnable {
// source omitted. just emphasizing you need one of these for each "step".
// if you don't need to set Result, this could be a static inner class.
}
#Override
public Object doInBackground(Void...) {
final ExecutorService es = Executors.newSingleThreadExecutor();
final ConditionVariable cv = new ConditionVariable(false);
try {
es.submit(new TheFirstTask(es, cv));
// you can choose not to timeout at this level and simply block until something happens...
final boolean done = cv.block(timeout);
if(!done) {
// you will need to account for unfinished threads, see finally section!
return new IllegalStateException("timed out waiting on completion!");
}
if(result != null) {
final ResultTask done = result.get();
if(done instanceof DoneTask) {
// pass SomeType to onPostExecute()
return ((DoneTask<SomeTYpe>)done).getResults();
}
else if(done instanceof FailedTask) {
// pass Exception to onPostExecute()
return ((FailedTask)done).getError();
}
else {
// something bad happened, pass it to onPostExecute()
return new IllegalStateException("something unexpected signalled CV!");
}
}
else {
// something bad happened, pass it to onPostExecute()
return new IllegalStateException("something signalled CV without setting result!");
}
}
catch(Exception ex) {
// something outside workflow failed, pass it to onPostExecute()
return ex;
}
finally {
// naive shutdown (doesn't interrupt running tasks): read JavaDoc on ExecutorService for details
es.shutdown();
}
}
#Override
public void onPostExecute(Object result) {
if(result instanceof SomeType) {
// success UI
}
else if(result instanceof Exception) {
// error UI
}
}
}
I can't say for sure without knowing the details of your use case, but you probably want to avoid the SynchronousQueue, as it will block the thread putting things into the queue until the listener thread takes it back out of the queue. If you were putting things in using the UI thread you'd be locking up the UI.
I think a BlockingQueue may suit your needs. The JavaDoc has a good producer-consumer example.

Categories

Resources