Throw a custom exception from a service to an activity - android

I'm currently working on an XMPP app' on Android and I'm pondering about the best way to throw a different type of Exception than a RemoteException to my activity from my service.
As it seems impossible to throw another thing than a RemoteException using IPC (you can't declare to throw anything in your .aidl), I just see two solutions:
Create a listener for my activity to listen on my custom XMPP exception, which in fact will not be thrown but just sent as a usual object implementing the Parcelable protocol.
Catch my XMPPException and throw a RemoteException (with a content updated with my XMPPException) - But in that case, how could I know on my activity if it's an XMPP or a real RemoteException ? By tagging the name of the exception and parsing it on my activity ? It would be really gore.
Do you have any idea ? Did I miss something from the SDK documentation ?
Thanks.

If #1 means what I think it does, I'd use that -- have the service catch the exception and call a method on an AIDL-defined callback object created and supplied by the activity.
You can see an example of that technique in this client and service project, from one of my books.

It looks like we can throw custom exceptions derived from RemoteException. So you can have XMPPRemoteException, or just a generic MyRemoteException that will hold the original exception. Below is a demo for the second case:
Server:
try {
...
}
catch(XMPPException e) {
throw new MyRemoteException(e);
}
Client:
try {
service.someCall();
}
catch(MyRemoteException e) {
rethrow(e);
}
Helper method:
private void rethrow(MyRemoteException e) throws Exception {
if(e.innerException instanceof XMPPException)
throw (XMPPException)e.innerException;
else
throw e.innerException;
}
Exception:
public class MyRemoteException extends RemoteException {
private static final long serialVersionUID = 1L;
public Exception innerException;
public MyRemoteException() {}
public MyRemoteException(Exception innerException) {
this.innerException = innerException;
}
}

I think it is impossible to achieve "Throw a custom exception from a service to an activity".
See the resource of Parcel:
/**
* Use this function for customized exception handling.
* customized method call this method for all unknown case
* #param code exception code
* #param msg exception message
*/
public final void readException(int code, String msg) {
switch (code) {
case EX_SECURITY:
throw new SecurityException(msg);
case EX_BAD_PARCELABLE:
throw new BadParcelableException(msg);
case EX_ILLEGAL_ARGUMENT:
throw new IllegalArgumentException(msg);
case EX_NULL_POINTER:
throw new NullPointerException(msg);
case EX_ILLEGAL_STATE:
throw new IllegalStateException(msg);
}
throw new RuntimeException("Unknown exception code: " + code
+ " msg " + msg);
}
so we can know that we just can throw these five exceptions above.
for example:
If your service throw a IllegalArgumentException:
#Override
public void addImage(final int align, final byte[] imageData) throws RemoteException {
log("/// addImage ///");
if (imageData == null) {
throw new IllegalArgumentException("The second argument(image data) can not be empty!");
}
...
}
your client will can catch it:
try {
printer.addImage(0, null);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}

Related

Throw exception and allow to proceed in method further

I was working on some validation. There is some mandatory fields and some of them are optional. For mandatory fields, I'm throwing exception, but for optional fields, I've to print warning and have to proceed further in my method. I'm not getting any way to doing warning part. Can someone help on it?
public void method(String param1, String param2){
if(param1 == null){
throw new IllegalArgumentException("mandatory field");
}
//Here for param2, I want to throw eception, but want to proceed further to next line.
//Execute my code here
}
This is not how exceptions work. There are several ways to solve it:
Just don't use exceptions and print your error instead (println() or some textfield, toast or whatever)
Place a boolean marker saying that param2 failed and throw your exception at the end of the method
m_param2 = true
//...
if (param2 == null) {
m_param2 = false
}
// you proceed here
if (!m_param2){
// throw exception
}
Use submethods for the parameter-check which always throw an exception when errors occur and catch the error in your main-method and decide what to do then.
For me case 3 does not make that much sense but that depends on how and when you want to print the message. If you have something in the parent layer (the code that runs your method) that automatically generates the error-message when an exception occurs, I would stick to my second suggestion.
In general I think that missing optional parameters are no real error case so that no exception should be thrown. The method-caller needs to pass the parameter anyhow (though it can be null, of course).
throw is a keyword which finishes the method execution you cant continue by throwing an exception you can use an interface to do what you want
public void method(String param1, String param2,Listener listener){
if(param1 == null){
listener.IllegalArgumentException("mandatory field");
return;
}
listener.IllegalArgumentException("mandatory field");
//Execute my code here
}
interface Listener{
void IllegalArgumentException(String string);
}
You can use
try{
} catch (Exception e){
// you can ignore if you want to
}finally {
//rest of your code here
}
try the below code let me know if any issues.
public void method(String param1, String param2){
if(param1 == null){
throw new IllegalArgumentException("mandatory field");
}
if(param2 == null) {
Log.d("Error", "param2 is null");
}
}

Android MVP: Error Handling from Model class / manually trigger error

I have read the articile , and the great solution provided is working perfectly in Activity environment.
I tested it with
int a = 1/0;
in onCreate. And the custom exception handler did triggered.
Currently my app adopted MVP architecture. There are some codes implemeted in Model or Presenter layer like
try {
data = getStringFromFile(fileLocation);
} catch (Exception e) {
e.printStackTrace();
}
which might throw exception. However, the exceptions that caught within Presenter or Model layer is not triggering the default exception handler.
What should I do in order to makes the throwable exception from Model or Presenter layer triggers the custom UncaughtExceptionHandler I had created?
And also, is there anyway to trigger the custom UncaughtExceptionHandler manually by using my self defined exception.
Wrap the code in your presenter in try catch and then throw the exception from catch block to handle it by the parent class:
public void getData() throws Exception
try {
int a = 1/0;
} catch (Exception e) {
throw e;
}
}

QuickBlox Attachment issue in Android

In group chat I am attaching single file, while sending the QBMessage object has on 1 attachment but on receive that QBMessage object the same attachment comes twice.
This happens only in group chat. In private chat it works properly
Seems like you are using samples from here as a starting point for your application: https://github.com/QuickBlox/quickblox-android-sdk
I had the same bug with it, so my quick solution was override sendMessage method in GroupChatImpl.java
#Override
public void sendMessage(QBChatMessage message) throws XMPPException, SmackException.NotConnectedException {
if (qbChat != null) {
try {
qbChat.sendMessageWithoutJoin(message);
} catch (SmackException.NotConnectedException | IllegalStateException e) {
}
}
}

Android: How to check for a specific exception?

How to check for a specific exception, e.g. SocketException with message "Socket closed"? We can compare strings like this:
if (exception.getMessage().equals("Socket closed"))...
but is there some more elegant method, like comparing error codes, or comparison with constant exception value?
Except if SocketException is always "Socket closed", but in docs it states that this class is a superclass for all socket exceptions, so there is more than one.
UPDATE:
I don't want to check for exception class. If I do, I would use specialized catch rather than to check tor a class explicitly:
catch (SocketException ex) { ... }
I want some more elegant method to distinct two exceptions which are instances of the same class, not by comparing strings like this:
try {
int i = 2;
if (i == 1) throw new SocketException("one");
else if (i == 2) throw new SocketException("two");
}
catch (SocketException ex) {
if (ex.getMessage().equals("one")) { ... }
}
In this particular case I throw exceptions to show what is it about, but in reality it can be code not controlled by me.
Also I noticed that exception message in one particular case method threw "Socket closed", in another different method threw "Socket is closed". So it's not so reliable to stick to the message either.
Your question has different approaches, depending on what you are trying to achieve. The simplest method for determining if you have the exception you want is to use instanceof since an Exception is a class as well, i.e.:
if (myException instanceof SocketException) {
...
}
However, you then add the requirement of the contents of the message or the possibility that the Exception thrown is actually a subclass of the Exception of interest to you. In the case of a "subclass" you can check if it is a subclass with:
if (myException instanceof SocketException &&
myException.getClass() != SocketException.class) {
// then I'm an instance of a subclass of SocketException, but not SocketExcpetion itself
}
Or conversely, only evaluate for the parent class:
if (myException instanceof SocketException &&
myException.getClass() == SocketException.class) {
// then I'm an instance of the class SocketException, and not a cubclass of SocketExcpetion!!
}
These serve as the "error codes" you seem to be looking for - the identification of the class, with certainty.
However, if you really are interested in the human-readable error contents, then the solution you have should be your implementation. That seems unlikely, but sometimes that is what is required.
You can use:
exception.getClass().getSimpleName() and compare it to SocketException
Hope this helps.

Retrofit custom error handler + sync & asyc requests

I have a custom error handler that checks RetrofitError it gets passed and rethrows it as custom exceptions
private static ErrorHandler getErrorHandler() {
return new ErrorHandler() {
#Override
public Throwable handleError(RetrofitError cause) {
switch (cause.getKind()) {
case NETWORK: return new NetworkException(cause);
case HTTP: return new ApiException(cause);
default: return cause;
}
}
};
}
If this is my endpoint
#GET(USERS_GET_URL)
User getUsers() throws NetworkException, ApiException;
while executing synchronous request I try...catch and handle each custom exception as I want. When it is done asynchronously using
#GET(USERS_GET_URL)
void getUsers(Callback<User> cb) throws NetworkException, ApiException;
the handled exception gets rethrown as RetrofitError. The following snippet of code is from CallbackRunnable class of Retrofit which executes the request
try {
final ResponseWrapper wrapper = obtainResponse();
callbackExecutor.execute(new Runnable() {
#Override public void run() {
callback.success((T) wrapper.responseBody, wrapper.response);
}
});
} catch (RetrofitError e) {
Throwable cause = errorHandler.handleError(e);
final RetrofitError handled = cause == e ? e : unexpectedError(e.getUrl(), cause);
callbackExecutor.execute(new Runnable() {
#Override public void run() {
callback.failure(handled);
}
});
}
As it can be seen, my custom exceptions are getting rethrown as RetrofitError which makes me loose valuable information. Is there any way I can bypass custom error handling for just the async requests?
In your ErrorHandler you pathing original RetrofitError as cause, so as result in your Callback#failure(RetrofitError error) to get actual information you need to write next code: error.getCause().getCause(). This error will contain response that server send with all the data.
But error handler was created for sync request and after some time square team decided to close this gap this way. For more info you can read: https://gist.github.com/benvium/66bf24e0de80d609dac0
As for me, I don't recommend to use ErrorHander for async way, because I don't find any good solution to handle different types of error. It was much easier to get data right from initial RetrofitError.

Categories

Resources