Question

So I'm writing an Android application in Java based on an iOS application that I am also working on, but this question is more asking about how to communicate callback mechanism (like blocks in Objective-C 2.0) in Java.

This application involves networking, authenticating and communicating with a server via an API.

I am using this framework: https://github.com/loopj/android-async-http

I am trying to encapsulate all of the networking model into classes to make everything clean and easy (it seems so easy in iOS with delegates and blocks, but java doesn't appear to have ANY of these conveniences). So, I am using this as a guide for callbacks: http://www.gdgankara.org/2013/03/25/android-asynchronous-http-client-a-callback-based-http-client-library-for-android-and-android-smart-image-view/

Now lets say I don't want to make a call from an Activity class, but an API class, which can be called from an Activity class, how can I do this? I know easily how to do this with blocks and delegates in iOS, but how can I do this with interfaces?


For Example:

In iOS (using a common networking framework called AFNetworking), I have 4 classes:

HTTPClient.h/m

+(id)sharedHTTPClient
  {
    static dispatch_once_t pred = 0;
    __strong static id __httpClient = nil;
    dispatch_once(&pred, ^{
        NSString *baseURL = http://baseurl.com;
        __httpClient = [[self alloc] initWithBaseURL:[NSURL URLWithString:baseURL]];
        [__httpClient setParameterEncoding:AFJSONParameterEncoding];        

    });
    return __httpClient;
}

APILogin.h/m

-(void)loginWithSuccessBlock:(void (^)(NSArray *responseArray))loginSuccess {
    HTTPClient *httpClient = [HTTPClient sharedHTTPClient];
    NSURLRequest *request = [httpClient requestWithMethod:@"GET" path:@"/api/login" parameters:nil];
    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        NSArray *response = [self.jsonParser parseResponseFromJSON:JSON];
        if (loginSuccess) {
            loginSuccess(response);
        }

    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {  
        [APIErrorHandler handleError:error withHTTPResponse:response];
    }];

    [operation start];
}

LoginObject.h/m

-(id)init
 {
     self = [super init];
     if(self) {
         [self.apiLogin loginWithSuccessBlock:^ void (NSArray *loginArray) {
                //process the array
          }];
     }
 }

LoginVC.h/m

...
LoginObject *loginObj = [[LoginObject alloc] init];
...

So, now what I have so far, using the Android-Async-Http library is:

HTTPClient.java

public class HTTPClient extends AsyncHttpClient {
    public static HTTPClient sharedHTTPClient;
    public static String baseUrl = "http://baseurl.com";
    public HTTPClient {
        super();
    }
    ...
}

APILogin.java

public class APILogin {
    public void loginWithSuccessBlock() {
        HTTPClient httpClient = QHTTPClient.sharedHTTPClient;
    httpClient.get("/api/login", new JsonHttpResponseHandler() {
         @Override
         public void onSuccess(JSONArray response) {
             // Successfully got a response
            ArrayList<LoginObject> loginInfo = this.jsonParser.parseLoginFromJSON(response);
            **NEED TO DO A CALL BACK!! Like with the blocks in iOS**
         }
        @Override
         public void onSuccess(JSONObject response) {
             // Successfully got a response
            // shouldn't be an object
            throw new IllegalArgumentException();
         }


         @Override
         public void onFailure(Throwable e, String response) {
             // Response failed :(
         }
    });
}

LoginObject.java

public class LoginObject {
    public LoginObject {
        this.apiLogin.loginWithSuccessBlock(**something something for a callback**);
    }
}

Hopefully, I've made it a little clearer what I am trying to achieve. I want to be able to execute some kind of callback block on the object that called the api call, on success. However, it will not always be the same object. LoginObject may have an instance of APILogin.java and so might a different object, so I can't use the second link above in which you can specific a specific class and pass it in and call a method on it, because the classes will be of different types, and Java doesn't have a generic pointer (id or void*) object.

Was it helpful?

Solution

So I've discovered my own answer after trying many things and scouring the web for a possible solution. What I've come up with is to basically chain the response handlers.

So for:

public class APILogin {
    public void loginWithSuccessBlock(**final JsonHttpResponseHandler handler**) {
        HTTPClient httpClient = QHTTPClient.sharedHTTPClient;
        httpClient.get("/api/login", handler);
    }
}

public class LoginObject {
    public LoginObject {
        this.apiLogin.loginWithSuccessBlock(new JsonHttpResponseHandler(){
        ...
        );
    }
}

which isn't very robust because it doesn't let me do much customization, but it'll do.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top