Android rxJava Error handling with retrofit - java

I'm using the newer RX java where instead of
Observable.create(new Observable.OnSubscribeFunc<T>() {...});
this is used: (due to deprecation)
Observable.create(new Observable.OnSubscribe<T>() {...});
(This can be important as most example, tutorial, explonation uses the old one...)
Well, lets see my problem. I have a Java class, relevant parts from it:
private interface ApiManagerService {
#FormUrlEncoded
#POST("/login")
User getUser(#Field("username") String userName, #Field("password") String password);
}
private static RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(HOST)
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
private static ApiManagerService apiManager = restAdapter.create(ApiManagerService.class);
public static Subscription login(final String userName, final String password, Observer<User> observer) {
return Observable.create(new Observable.OnSubscribe<User>() {
#Override
public void call(Subscriber<? super User> subscriber) {
try {
User user = apiManager.getUser(userName, password);
subscriber.onNext(user);
subscriber.onCompleted();
} catch (RetrofitError e) {
subscriber.onError(e);
} catch (Throwable e) {
subscriber.onError(e);
}
}
}
).subscribeOn(Schedulers.io())
.retry(3)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
}
This code almost works perfectly, if everything is ok. But if I make an intentional error, like I turn off the WiFi.. than retrofit get the "UnKnownHostException"... as it should happen at the retrofit call (getUser) in the try catch block. But instead of handling the error to onError(Throwable t) --> where I could handle, it just crashes the app. So it is like if the error never gets to the catch block.
What is strange that HTTP errors (like 404, 401 etc.) is catched, got by onError(...) and everything is just fine.
Everything goes for 3 times before crash, as of .retry(3) but none gets into catch clause.
EDIT 1
LogCat Output:
01-08 16:19:31.576 15285-16162/asd.bdef.gh D/Retrofit﹕ ---- ERROR https://testapi.com/api/login
01-08 16:19:31.606 15285-16162/asd.bdef.gh D/Retrofit﹕ java.net.UnknownHostException: Unable to resolve host "testapi.com": No address associated with hostname
at java.net.InetAddress.lookupHostByName(InetAddress.java:394)
at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
at java.net.InetAddress.getAllByName(InetAddress.java:214)
at com.squareup.okhttp.internal.Network$1.resolveInetAddresses(Network.java:29)
at com.squareup.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:259)
at com.squareup.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:233)
at com.squareup.okhttp.internal.http.RouteSelector.nextUnconnected(RouteSelector.java:159)
at com.squareup.okhttp.internal.http.RouteSelector.next(RouteSelector.java:133)
at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:314)
at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:237)
at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:423)
at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:105)
at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:239)
at com.squareup.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)
at com.squareup.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:25)
at retrofit.client.UrlConnectionClient.prepareRequest(UrlConnectionClient.java:68)
at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:37)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:321)
at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
at retrofit.RestAdapter$RestHandler$1.invoke(RestAdapter.java:265)
at retrofit.RxSupport$2.run(RxSupport.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at retrofit.Platform$Android$2$1.run(Platform.java:142)
at java.lang.Thread.run(Thread.java:841)
01-08 16:19:31.606 15285-16162/asd.bdef.gh D/Retrofit﹕ ---- END ERROR
01-08 16:19:31.977 15285-15285/asd.bdef.gh D/AndroidRuntime﹕ Shutting down VM
01-08 16:19:31.977 15285-15285/asd.bdef.gh W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x41c9d8b0)
01-08 16:19:31.977 15285-15285/asd.bdef.gh E/AndroidRuntime﹕ FATAL EXCEPTION: main
the given api address is not the real one, but the real one is reachable. I just turned off the WiFi to test error handling.
And one more use-case: If I add to the observable .onExceptionResumeNext([2nd observable]) than it goes to the 2nd observable, and it not crashes. But this is not the solution of the problem.
EDIT 2
ApiManager.login(userName, pass, new Observer<User>() {
#Override
public void onCompleted() { }
#Override
public void onError(Throwable e) {
DialogManager.showBasicErrorDialog(getApplicationContext(), e.getLocalizedMessage());
logger.showLog("Login Not ok");
e.printStackTrace();
}
#Override
public void onNext(User user) {
logger.showLog("login ok, user: " + user.getName().toString());
{...}
}
});
EDIT 3
FATAL EXCEPTION: main
rx.exceptions.OnErrorFailedException: Error occurred when trying to propagate error to Observer.onError
at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:175)
at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:97)
at rx.internal.operators.NotificationLite.accept(NotificationLite.java:144)
{...}
Caused by: java.lang.NullPointerException: Attempt to read from field 'rx.functions.Action0 rx.schedulers.TrampolineScheduler$TimedAction.action' on a null object reference
at rx.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:85)
Thanks in advance for helping.

You don't have to build your own Observable with Retrofit, as Retrofit can directly return Observable:
http://square.github.io/retrofit/
Retrofit also integrates RxJava to support methods with a return type
of rx.Observable
#GET("/user/{id}/photo") Observable getUserPhoto(#Path("id")
int id);
(You won't have to handle errors by yourself)
Can you post the stacktrace of your crash ? As I think like you, that your application shouldn't crash.

It looks like you may be running into an issue has been fixed as of RxJava 1.0:
TrampolineScheduler NullPointerException

Related

Coroutine cancellation with HMS

I'm adapting my application to HMS. When I cancel launched coroutine, catch and trying to log CancellationException to HMS crashlytics, my app crashed with strange logs. If I omit this exception and didn't log it to crashlytics using method AGConnectCrash.getInstance().recordException(throwable) coroutine cancellation doesn't lead to app crash. Can someone help with that problem?
Crash logs
java.lang.ArrayIndexOutOfBoundsException: length=0; index=0 at com.huawei.agconnect.crash.internal.bean.Event$Builder.summary(Unknown Source:5) at com.huawei.agconnect.crash.internal.log.AGCCrashNonFatal.collectInfo(Unknown Source:41) at com.huawei.agconnect.crash.internal.log.AGCCrashNonFatal.logException(Unknown Source:0) at com.huawei.agconnect.crash.internal.log.AGCCrashCore$4.run(Unknown Source:6) at java.util.concurrent.ThreadPoolExecutor.processTask(ThreadPoolExecutor.java:1187) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:784)
SomeCodeExample
private fun loadData() {
job?.cancel()
job = viewModelScope.launch {
try {
data.value = someApiCall()
} catch (e: Exception) {
Logger.log(e)
}
}
}
Where
object Logger {
fun log(e: Throwable?) {
if (e != null) {
AGConnectCrash.getInstance().recordException(e)
}
}
}
I think your input parameter type is incorrect. You put the string instead of the stack information. You are advised to enter the document type. If a character string is forcibly entered, the system crashes. And in later versions, a judgment protection mechanism will be added.
For Details,pls kindly refer Docs.

FATAL EXCEPTION: CameraX-audio encoding thread

I am recording videos using the camera X library. When i take video for 5 seconds before that (i,e)two seconds if i close the video its crashing with above error.How to handle this run time exception in android cameraX library
E/AndroidRuntime: FATAL EXCEPTION: CameraX-audio encoding thread
Process: .debug, PID: 4625
java.lang.IllegalStateException
at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)
at android.media.MediaCodec.dequeueOutputBuffer(MediaCodec.java:2698)
at androidx.camera.core.VideoCapture.audioEncode(VideoCapture.java:705)
at androidx.camera.core.VideoCapture$1.run(VideoCapture.java:340)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:201)
at android.os.HandlerThread.run(HandlerThread.java:65)
sometimes the below issue
FATAL EXCEPTION: CameraX-video encoding thread
Process: <packagename>, PID: 10794
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.media.MediaCodec.dequeueOutputBuffer(android.media.MediaCodec$BufferInfo, long)' on a null object reference
at androidx.camera.core.VideoCapture.videoEncode(VideoCapture.java:604)
at androidx.camera.core.VideoCapture$2.run(VideoCapture.java:348)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.os.HandlerThread.run(HandlerThread.java:65)
in this samples also not fixed yet
https://github.com/android/camera-samples/issues/2#issuecomment-546812852
By adding a callback to videoCapture.startRecording(videoFile, executor, onVideoSavedCallback); you should be able to handle the exeption in the onError method.
/**
* Define callback that will be triggered after a video has been taken and saved to disk
*/
private VideoCapture.OnVideoSavedCallback onVideoSavedCallback= new VideoCapture.OnVideoSavedCallback() {
#SuppressLint("RestrictedApi")
#Override
public void onVideoSaved(#NonNull File file) {
Log.d("VIDEO_CAPTURE", "Video capture succeeded");
}
#Override
public void onError(int videoCaptureError, #NonNull String message, #Nullable Throwable cause) {
Log.e("VIDEO_CAPTURE", "Video capture failed");
if (cause != null) {
cause.printStackTrace();
Toast.makeText(context,"Video capture failed",Toast.LENGTH_LONG).show();
}
}
};

DBFlow SQLite.delete() throwing java.lang.IllegalArgumentException: Please use query()

I one of the from projects I have DBFlow library for SQLite.
The problem occurs when I'm trying to remove some data from Table.
override fun removeOldEventPlanners(): Single<Boolean> {
LogMgr.v(TAG, "removeOldEventPlanners()")
return Single.create { emitter ->
RXSQLite.rx(SQLite.delete().from(EventPlanner::class.java)
.where(EventPlanner_Table.date_to.lessThan(Date(TimeUtil.getCurrentTime().time - CONST_30_DAYS_IN_MILLISECONDS)))
.or(EventPlanner_Table.deleted.`is`(1)))
.queryList()
.subscribe({ eventPlanners ->
LogMgr.d(TAG, "removeOldEventPlanners queryList() $eventPlanners")
emitter.onSuccess(true)
}, { throwable ->
LogMgr.e(TAG, "removeOldEventPlanners error", throwable)
emitter.onError(throwable)
})
}
}
This code throwing exception:
java.lang.IllegalArgumentException: Please use query(). The beginning is not a ISelect
at com.raizlabs.android.dbflow.sql.language.Where.checkSelect(Where.java:259)
at com.raizlabs.android.dbflow.sql.language.Where.queryList(Where.java:235)
at com.raizlabs.android.dbflow.rx2.language.RXModelQueriableImpl$2.call(RXModelQueriableImpl.java:61)
at com.raizlabs.android.dbflow.rx2.language.RXModelQueriableImpl$2.call(RXModelQueriableImpl.java:58)
at io.reactivex.internal.operators.single.SingleFromCallable.subscribeActual(SingleFromCallable.java:44)
at io.reactivex.Single.subscribe(Single.java:3575)
at io.reactivex.Single.subscribe(Single.java:3561)
at com.fs.wfm.storage.dbflow.DBFlowWfmStorageRepo$removeOldEventPlanners$1.subscribe(DBFlowWfmStorageRepo.kt:112)
at io.reactivex.internal.operators.single.SingleCreate.subscribeActual(SingleCreate.java:39)
at io.reactivex.Single.subscribe(Single.java:3575)
at io.reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89)
at io.reactivex.internal.schedulers.ScheduledDirectTask.call(ScheduledDirectTask.java:38)
at io.reactivex.internal.schedulers.ScheduledDirectTask.call(ScheduledDirectTask.java:26)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:841)
Anyone has an idea how to fix it?
delete does not return values, so using queryList() to return values as list is not correct and can be seen in the stacktrace.

"INVITE SESSION ALREADY TERMINATED ERROR" while trying to handle incoming call via pjsip(PJSUA2)

I have successfully made outgoing call via PJSIP. Now facing a problem while try to handle incoming call.
Thread isanycall=new Thread(new Runnable() {
#Override
public void run() {
while(true)
{
if(Global.isanycall==1)
{
sipOperationIncoming(username, pwd, ip, number.getText().toString());
Global.isanycall=0;
}
}
}
});
isanycall.start();
This code is checking if there is any incoming call.
System.out.println("Incoming call handler");
//sip operation started
registration=SipRegistration.getSipRegistration(uname,pwd,ip);
registration.answerCall(da);
//sip operation ended
This code block is just responsible to call a function answerCall which is as follow
public void answerCall(DialerActivity activity){
call=new MyCall(myacc,1,this.ep,activity);
CallOpParam prm = new CallOpParam();
prm.setStatusCode(pjsip_status_code.PJSIP_SC_RINGING);
try {
call.answer(prm);
}catch(Exception e){
e.printStackTrace();
}
}
Now the exception I am getting is
java.lang.Exception: Title: pjsua_call_answer2(id, param.p_opt, prm.statusCode, param.p_reason, param.p_msg_data)
10-27 12:11:19.839 10090-10384/com.skyteloutsourcing.callnxt W/System.err: Code: 171140
10-27 12:11:19.839 10090-10384/com.skyteloutsourcing.callnxt W/System.err: Description: INVITE session already terminated (PJSIP_ESESSIONTERMINATED)
What can be the reason?
Solved it, I was responding with a different call id rather than which was the call id of incoming call. :)
I faced this error when I don't check this control
if(ci.state==pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED){
currentCall.delete()
currentCall=null
}

nullpointerexception error. trying to connect to the bitcoin server from my phone

I am fairly new to android, java, and mainly jsonrpc...
I have been stuck on this error for some time and i dont know if it is how i have coded it that is causing the issue or if i am trying to connect to the wrong server...
If you could help, it would be GREATLY appreciated.
here is the error code and the important code:
09-08 12:36:12.141: W/System.err(30361): Network exception: failed to connect to /10.10.11.75 (port 18332): connect failed: ECONNREFUSED (Connection refused)
09-08 12:36:12.151: W/dalvikvm(30361): threadid=11: thread exiting with uncaught exception (group=0x417df2a0)
09-08 12:36:12.151: E/AndroidRuntime(30361): FATAL EXCEPTION: AsyncTask #1
09-08 12:36:12.151: E/AndroidRuntime(30361): java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:299)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
at java.util.concurrent.FutureTask.run(FutureTask.java:137)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
at java.lang.Thread.run(Thread.java:856)
Caused by: java.lang.NullPointerException
at com.bitcoinapp.MainActivity.connect(MainActivity.java:219
at com.bitcoinapp.MainActivity.access$0(MainActivity.java:157)
at com.bitcoinapp.MainActivity$BitcoinConnect.doInBackground(MainActivity.java:143)
at com.bitcoinapp.MainActivity$BitcoinConnect.doInBackground(MainActivity.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
09-08 12:36:12.151: E/AndroidRuntime(30361): ... 5 more
this is the android code that i am using at the moment... all of which is run once the user presses the button on the application. I am working off my SAMSUNG S3 MINI and not an emulator.
I have had to omit some of the content, so showing line numbers wont help, but i have added in the ones that i think are important...
class Connection implements OnClickListener {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
new BitcoinConnect().execute();
}
}
private class BitcoinConnect extends AsyncTask<String, Integer, Object[]> {
#Override
protected Object[] doInBackground(String... params) {
// TODO Auto-generated method stub
connect();
return null;
}
}
public class BasicAuthenticator implements ConnectionConfigurator {
public void configure(HttpURLConnection connection) {
// add custom HTTP header
connection.addRequestProperty("myusername", "mypassword");
}
}
private void connect() { //(line 157)
//This is the code for the JSONRPC2-CLIENT iteraction
// The JSON-RPC 2.0 server URL
URL serverURL = null;
try {
serverURL = new URL("http://10.10.11.75:18332");
} catch (MalformedURLException e) {
// handle exception...
e.printStackTrace();
}
// Create new JSON-RPC 2.0 client session
JSONRPC2Session mySession = new JSONRPC2Session(serverURL);
mySession.setConnectionConfigurator(new BasicAuthenticator());
//This is for the bitcoin BASE interaction.
//for the Bitcoin Payment Request
String method = "getinfo";
Map<String,Object> params = new HashMap<String,Object>();
String id = "Request001";
JSONRPC2Request payment = new JSONRPC2Request(method, params, id);
String jsonString = payment.toString();
JSONRPC2Response response = null;
Log.i("Failed0", "Failed0");
try {
response = mySession.send(payment);
Log.i("response", String.valueOf(response));
mTextView.setText((CharSequence) response);
} catch (JSONRPC2SessionException e) {
System.err.println(e.getMessage());
// handle exception...
Log.i("response", String.valueOf(response));
}
// Print response result / error
if (response.indicatesSuccess()) { //(line 219)
System.out.println(response.getResult());
} else {
System.out.println(response.getError().getMessage());
}
}
I am using the JSONRPC2.0 libraries for the base code and the client code. I am trying to connect to the bitcoin testnet server. The IP there is one of many that i have tried...
I know that testnet is on port 18332 and the mainnet is 8332...
ive tried a localhost IP and that hasnt worked either.
I dont know if there is suppose to be other code that i must use in order for my phone to connect to the bitcoin server...
Please help me, thanks in advance
Lets apply some logical thinking.
According to the stack trace, the NullPointerException was thrown here:
if (response.indicatesSuccess()) {
That means response was null. (No other alternative!)
That means that the send call in
response = mySession.send(payment);
EITHER returned assigned null to response, OR it through a JSONRPC2SessionException that you caught.
I suspect it was the latter, and that the message "Network exception: failed to connect to /10.10.11.75 (port 18332): ..." was logged in the process. However, the evidence is not convincing. (There aren't any "I/..." lines in the logcat output ...)
In summary, what you have done is catch the exception that told you that the send has failed, and then proceed to try to process the non-existent response!
The underlying problem is that you app cannot connect to 10.10.11.75 on port 18332. I assume that you realize that 10.10.11.75 is a private IP address, and hence that you will only be able to connect to it if the server is on your local network.

Categories