Chunked streaming not behaving as expected Retrofit+RxJava - android

#GET("poll/session/{sessionId}/details")
Observable getSessionDetails(#Path("sessionId") String sessionId);
#GET("poll/session/{sessionId}/details")
#Streaming
Observable getSessionDetails(#Path("sessionId") String sessionId);
#Override
public Observable getSessionDetails(String sessionId) {
return sessionAPI.getSessionDetails(sessionId)
.flatMap(responseBody -> events(responseBody.source()));
}
public static Observable<String> events(BufferedSource source) {
return Observable.create(subscriber -> {
try {
while (!source.exhausted()) {
subscriber.onNext(source.readUtf8Line());
}
} catch (IOException e) {
e.printStackTrace();
subscriber.onError(e);
}
subscriber.onCompleted();
});
}
The events() method does not get called unless all the chunks are done.
But the chunked streams are expected to be delivered chunk by chunk, which does not seem to be happening.
I have tried with and without the #Streaming annotation to the API, yet the behaviour is same.
I had used Android Retrofit 2 + RxJava: listen to endless stream as a reference to do my implementation

Alright guys I found the answer. It was because I was logging with the Body Attribute
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
So, since the logger is waiting for the whole body to print it, it was behaving the way as mentioned in the problem.
reference : Square's Retrofit response parsing logic: streaming?

Related

Poll a URL and return a true when the response contains a string

I'm modifying an app and wondering if someone can point me in the right direction. Basically, I want the app to poll a URL and in the json response, if a value is true, then continue on.
The current code has this:
return prepareForUpgrade() &&
uploadImage(firmware) &&
checkUpgradeStatus() &&
rebootDevice();
private boolean prepareForUpgrade() {
Timber.i("Preparing...");
try {
Response<ResponseBody> prepare = DeviceRestApi.prepareFirmwareUpgrade(
Constants.Device.DEFAULT_USERNAME,
Constants.Device.DEFAULT_PASSWORD,
DeviceRestApi.COMMAND_PREPARE
).execute();
boolean result = prepare.isSuccessful();
Timber.i("Result: %s", result);
return result;
} catch (IOException e) {
Timber.e(e, "Preparation failed");
return false;
}
}
Basically, the process continues on if the network request was successful, but I want to replace that behavior with something that polls a URL and the URL says when its successful.
Don't need a solution exactly, just wondering which way to go. Should I try a Service? An IntentService? Something else?

RxJava Zip Operator Error Handling with Iterator

Background
I have a process that uses RxJava to get data from different locations based on a list. Each item is got through a different method (all returning Observables.). Due to having N items to get the logic operator to use is zip with an iterator.
The Problem
The code below works as expected but it seems "wrong" that I need a try-catch block to catch the Exception that is thrown by getBigFoo() - that returns a FooNotFoundException. Do not the other error related operators cover this, such as onErrorResumeNext() and onErrorReturn()?
private Observable<Bar> processFoos(List<Foo> foos) {
List<Observable<? extends IBar>> observablesToZip = new ArrayList<>();
for(Foo foo : foos) {
switch (foo.getType()) {
case BIG_FOO :
try {
observablesToZip.add(getBigFoo(foo.getId()));
} catch (Exception exception) {
//do nothing - but this seems wrong
}
}
}
return Observable.zip(observablesToZip, results -> mergeFoosIntoBar(results));
}
Attempts Made
The attempt below doesn't seem to catch the Exception generated. I don't understand why as there are technically no upstream or downstream items in the sequence, so Observable.empty() should work?
private Observable<Bar> processFoos(List<Foo> foos) {
List<Observable<? extends IBar>> observablesToZip = new ArrayList<>();
for(Foo foo : foos) {
switch (foo.getType()) {
case BIG_FOO :
observablesToZip.add(getBigFoo(foo.getId().onErrorResumeNext(Observable.empty()));
}
}
return Observable.zip(observablesToZip, results -> mergeFoosIntoBar(results));
}
You may want to use defer. getBigFoo should not throw an exception but instead return an Observable in error. So defer may help you to fix it :
Observable<IBar> obs = Observable.defer(() -> {
try {
return getBigFoo(foo.getId());
} catch (Exception ex) {
return Observable.error(ex);
}
});
observablestoZip.add(obs);
#dwursteisen was on to the right answer, but wasn't quite there.
My issue was that I was throwing a new FooNotFoundException:
throw new FooNotFoundException()
But what I needed to do was:
return Observable.error(new FooNotFoundException());
Then in my Zip function:
observablesToZip.add(getBigFoo(foo.getId())).onExceptionResumeNext(Observable.just(null);
Using the above combination means that the overall sequence does not abort and return an error when the individual Observables are resolved and potentially throw errors.
Could you make getBigFoo(foo.getId()) throw RuntimeException instead Exception?. All Exceptions on Pipeline must be captured, but not runtimeExceptions.
Take a look to this silly example
/**
* Here is a silly example how runtimeExceptions are not needed
*/
#Test
public void observableRuntimeException() {
Integer[] numbers = {0, 1, 2, 3, 4, 5};
Observable.from(numbers)
.doOnNext(number -> throwRuntimeException())
.doOnError(t -> System.out.println("Expecting illegal argument exception:" + t.getMessage()))
.subscribe();
}
private void throwRuntimeException() {
throw new RuntimeException();
}
you can see more examples here https://github.com/politrons/reactive

Log all calls to .tranceive()

Is there a way to log the binary data send to the tranceive method of a NFC tag? https://developer.android.com/reference/android/nfc/tech/NfcV.html#transceive(byte[])
I am trying to find the last few missing pieces in a protocol and it would help if I could listen to the data getting sent.
I'm guessing that:
You want to monitor the APDUs/bytes sent from an app you have installed.
You've already searched for info about that specific protocol and found nothing.
At the Logcat, no relevant info is shown (by default).
Looking up at the transceive source code
public byte[] transceive(byte[] data) throws IOException {
return transceive(data, true);
}
which redirects to:
byte[] transceive(byte[] data, boolean raw) throws IOException {
checkConnected();
try {
TransceiveResult result = mTag.getTagService().transceive(mTag.getServiceHandle(),
data, raw);
if (result == null) {
throw new IOException("transceive failed");
} else {
return result.getResponseOrThrow();
}
} catch (RemoteException e) {
Log.e(TAG, "NFC service dead", e);
throw new IOException("NFC service died");
}
}
Which goes on to the TransceiveResult class.
My best bet (if you wish to get to the very end) is to recompile an Android source code that prints out the data input'd to the byte[] transceive(byte[] data) function. Good luck.
EDIT: Another option I happened to realise is to use an APDU sniffer, although I legitimately don't know how legal this option is.

A annotation on the volley note to avoid leaking

The code on the CacheDispatcher is as below. And focus on that release previous request object to avoid leaking request object when mQueue is drained.
I do not know why. Can anyone tell me the reason?
Thanks in advance.
java
Request<?> request;
while (true) {
// release previous request object to avoid leaking request object when mQueue is drained.
request = null;
try {
// Take a request from the queue.
request = mCacheQueue.take();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
}
request = mCacheQueue.take(); is a blocking call so when the queue is empty(drained) we will still keep reference of the old request while waiting if we didn't do request = null;
this however is not the best way to achieve this behavior and it was changed in the new Volley code to :
while (true) {
try {
// Get a request from the cache triage queue, blocking until
// at least one is available.
final Request<?> request = mCacheQueue.take();

Apache HTTPGet behaving weirdly in Android

I am trying to perform a simple get request using Apache HTTPClient however it seems as if all the code after the HTTPResponse response = client.execute(get); is being skipped. I am not able to access the contents of the response object,they are all null. However when I use debug mode and I explore the object I see all the data. This function is wrapped in an async task so I am wondering the task itself is not waiting on it to be executed or something I am not sure.
Something similar happened here:
Android code after httpclient.execute(httpget) doesn't get run in try (using AsyncTask)
Here is the code.
#Override
public T execute()
{
utils = new GeneralUtils();
if(getURL() == null)
{
throw new NullPointerException("No path specified");
}
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(getURL());
Log.e(TAG,"client created");
if(getHeaders()!=null)
{
Log.e(TAG,"client created");
for(Map.Entry<String,String> header:getHeaders().entrySet())
{
get.addHeader(header.getKey(),header.getValue());
}
}
try
{
HttpResponse response = client.execute(get);
Log.e(TAG,"executed");
if(response==null)
Log.v(TAG,"its null as heell");
Log.v(TAG,response.getStatusLine().getReasonPhrase());
Log.v(TAG,String.valueOf(response.getStatusLine().getStatusCode()));
Log.e(TAG,getURL());
Log.v(TAG,"everything else is dead");
for(Header header:response.getAllHeaders())
{
Log.v(TAG,header.getName()+" "+header.getValue());
}
if(response.getStatusLine().getStatusCode() == 200)
{
if(response.getEntity().getContent()!=null)
{
try
{
if(utils.isExternalStorageWritable())
{
String path = getContext().getFilesDir().getAbsolutePath()+"/"+getFileCategory()+"/" +getAlarmId()+getFileExtension();
media = new File(path);
/**
* if the directory has not being created this function does the creation.
*/
media.mkdirs();
FileOutputStream fileOutputStream = new FileOutputStream(media);
IOUtils.copy(response.getEntity().getContent(),fileOutputStream);
fileOutputStream.close();
Log.e(TAG,media.getAbsolutePath());
return (T)media;
}
return null;
}
catch (ClientProtocolException e)
{
Log.v(TAG,e.getMessage());
}
catch (IOException e)
{
Log.v(TAG,e.getMessage());
}
}
}
}
catch (IOException e)
{
Log.e(TAG, e.getCause().getMessage());
e.printStackTrace();
}
return null;
}
The code is not throwing any exceptions so I am not sure about what's happening.
All the code after the response object does not work. It just returns null, As in as soon as I try to obtain a value from response like so response.getStatusCode(), it seems as if the code goes dead and just returns null.
Why don't you use a library that will handle all these restful connections?
I would recommend a couple:
https://github.com/darko1002001/android-rest-client (this is mine i have to mention it first :). I have built this library for the projects i build. For your case you would supply a parser which will give you an InputStream which you will just save as a file (as you do it now with IO utils). It handles the Asynchronous part of the whole thing and generally gives you a nice way to organize code.
http://square.github.io/retrofit/ - is another one that i have been playing around with. i think it is pretty well made and should be able to do whatever you want with it.
http://java.dzone.com/articles/android-%E2%80%93-volley-library - Volley is a project that came out straight from Google and it was demoed at the last Google IO conference. It handles all the async operations for you as well and enables you to do all these things. One thing that i am not really sure about is whether or not it will enable you to parse the responses in the background thread.
I would strongly suggest for you to use one of these as they might save you a lot of time.
If you do want to continue with your code then i would suggest to first investigate if some of the "if" blocks you have are skipped, use the debugger or add log messages to see if it enters the blocks. Go step by step and see what goes wrong.
I am doing something similar in my project, check out this file:
https://github.com/darko1002001/android-rest-client/blob/master/android-rest-lib/src/main/java/com/dg/libs/rest/client/BaseRestClient.java

Categories

Resources