I have a retrofit interface that defines a method with a callback, like this one :
public interface ApiManagerService {
#GET("/users/")
void getUsers(Callback<List<GitHubMember>>);
}
GitHubMember is just a POJO with 3 fields : id, login and url. I created a class called ResponseHandler where I can wrap the response from the Callback. Here how it's define :
public class ResponseHandler<T> {
private T response;
private RESPONSE_CODE responseCode;
private String detail;
public static enum RESPONSE_CODE {
OK, // if request suceed
APP_ERROR, //technical error for instance network
TECHNICAL_ERROR // app technical error
}
//getters and setters
Here is how I use this class with the getUsers method :
public ResponseHandler<List<GitHubMember>> getUsers() {
ResponseHandler<List<GitHubMember>> handler = new ResponseHandler<List<GitHubMember>>();
apiManagerService.getUsers(new Callback<List<GitHubMember>> cb) {
#Override
public void success(List<GitHubMember> users, Response response) {
responseHandler.setResponse(users);
responseHandler.setResponseCode(ResponseHandler.RESPONSE_CODE.OK);
}
#Override
public void failure(RetrofitError error) {
try {
handler.setResponseCode(ResponseHandler.RESPONSE_CODE.APP_ERROR);
responseHandler.setDetail(error.toString());
}catch (Exception e){
handler.setResponseCode(ResponseHandler.RESPONSE_CODE.TECHNICAL_ERROR);
responseHandler.setDetail(e.getMessage());
}
}
}
return handler;
}
The problem that I have is after executing this method and entering the callback, all the fields in ResponseHandler are null. I am totally sure that the callbacks are executed because I set breakpoints in the callback while debugging.
The apiManagerService object is correctly initialized with the RestAdapter class.
How can I solve this problem?
apiManagerService.getUsers() only initiates network request and returns. Callback is called after network responded on the background thread. So by the time return handler is executed handler is still empty. More than that, even if somehow return-statement will be executed after callback, you may not see changes made to the shared variables (fields of handler) by background thread due to Java Memory Model restrictions.
Related
Java 11 introduced a new standard HTTP client. A request is sent using HttpClient:send, which returns a HttpResponse.
The HttpResponse::statusCode method can be used to find the HTTP status of the response.
HttpClient::send also takes a BodyHandler which is used to handle the body of the response. A useful family of BodyHandlers are those which wrap a Flow.Subscription, created with BodyHandlers::fromSubscriber and relatives. These are a useful way of dealing with infinite streams of data, such as server-sent events.
However, it seems that if you use one of these BodyHandlers, the flow is delivered on the thread which called HttpClient::send, and so for an infinite stream, that method never returns. Since it never returns, you never get a HttpResponse with which you can determine the status.
So, how do i get the status code for a response i subscribe to?
As noted in the documentation, these BodyHandlers
do not examine the status code, meaning the body is always accepted
with a hint that
a custom handler can be used to examine the status code and headers, and return a different body subscriber, of the same type, as appropriate
There does not seem to be a convenience method or class for this, but such a thing is moderately straightforward:
// a subscriber which expresses a complete lack of interest in the body
private static class Unsubscriber implements HttpResponse.BodySubscriber<Void> {
#Override
public CompletionStage<Void> getBody() {
return CompletableFuture.completedStage(null);
}
#Override
public void onSubscribe(Flow.Subscription subscription) {
subscription.cancel();
}
#Override
public void onNext(List<ByteBuffer> item) {}
#Override
public void onError(Throwable throwable) {}
#Override
public void onComplete() {}
}
// wraps another handler, and only uses it for an expected status
private static HttpResponse.BodyHandler<Void> expectingStatus(int expected, HttpResponse.BodyHandler<Void> handler) {
return responseInfo -> responseInfo.statusCode() == expected ? handler.apply(responseInfo) : new Unsubscriber();
}
// used like this
Flow.Subscriber<String> subscriber = createSubscriberSomehow();
HttpResponse<Void> response = HttpClient.newHttpClient()
.send(HttpRequest.newBuilder()
.uri(URI.create("http://example.org/api"))
.build(),
expectingStatus(200, HttpResponse.BodyHandlers.fromLineSubscriber(subscriber)));
I'm new with retrofit2 and I don't know how to return anything on the method OnResponse.
I have these code:
public boolean verificarUsuario (String login, String senha){
Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create(g)).build();
usuarioService service = retrofit.create(usuarioService.class);
retrofit2.Call<Boolean> user = service.verificarUsuario(login,senha);
user.enqueue(new Callback<Boolean>() {
#Override
public void onResponse(Call<Boolean> call, Response<Boolean> response) {
boolean result = response.body();
}
#Override
public void onFailure(Call<Boolean> call, Throwable t) {
}
});
}
And I need to return the variable result when my method atualizarUsuario is called.
Here I have the interface of my method verificarUsuario:
#GET("get/usuarios/login/{login,senha}")
Call<Boolean> verificarUsuario(#Path("login") String login, #Path("senha") String senha);
And here I have the Json of my method verificarUsuario:
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/verificarUsuario/")
public String verificarUsuario(#QueryParam("login")String login, #QueryParam("senha") String senha) {
usuarioDAO dao = new usuarioDAO();
if(dao.verificarUsuario(login,senha)){
return "true";
}else{
return "false";
}
}
Does anybody know how to do it?
Retrofit offers two types of calls, asynchronous calls and synchronous calls. Asynchronous calls are triggered by enqueue, which is the method you are calling, and let you pass in a Callback object to tell it what should happen when the call is done. If you want the calling method to wait for the response to come back and then return something based on that, you'll want to use the synchronous method instead, which is execute. However, you can't call execute on the UI thread in android, so if this is happening on the main thread, you'll need to make verificarUsuario return void, and then trigger whatever result you want in the callback you pass into enqueue
I have implemented a way of getting the result from onPostExecute back to my main activity. I wanted to know if this is the right thing I did, is there any more chance of improving it, and if it's not the best way, what is the best way?
This is what I have done:
public class MainClass implements AsyncResponse {
private MyAsyncTask asyncTask;
public MainClass() {
asyncTask = new MyAsyncTask();
asyncTask.asyncResponse = this;
}
public void startTask( {
asyncTask.execute("string");
}
#Override
public void processDone(String res) {
// got response in MainClass from onPostExecute
}
private class MyAsyncTask extends AsyncTask<String, String, String> {
protected AsyncResponse asyncResponse = null;
#Override
protected String doInBackground(String... urls) {
return "some processed string";
}
#Override
protected void onPostExecute(String res) {
this.asyncResponse.processDone(res);
}
}
}
Here's the AsyncResponse interface:
public interface AsyncResponse {
void processDone(String res);
}
I want to know in terms of processing speed that on an average android mobile device, would this be a good approach and if not, how do I improve it to make it a good approach?
Thanks.
I always done this way and never had any issues. I would say it is the best way.
in one Line without any callback
String s= new MyAsyncTask().execute().get();
You added an unnecessary interface - and perhaps it makes your code less usable.
First, if you create the AsyncTask as a class within your Activity there is no need for the interface. You can simply do this:
#Override
protected void onPostExecute(String res) {
processDone(res);
}
The AsyncTask will execute onPostExecute on the UI thread and you can call the Activity method without the interface.
Second, if you create AsyncTask outside the Activity class (for example, in its own java file) then you can use this method, except it is not a good idea because it will hold a reference to the Activity on another thread - it's a memory leak risk.
To avoid that, your interface should be implemented in a separate class, like AsyncTaskResponse.java that is passed to the AsyncTask class.
Last, AsyncTask provides the response in the form of a String if that is sufficient. You should look at the docs on AsyncTask:
https://developer.android.com/reference/android/os/AsyncTask.html
You are wrapping the AsyncTask inside another POJO class; doing this doesn't hurt, but provides little benefit.
Consider that when the task is completed, you will want a callback notification somewhere. Your MainClass will get a callback in processDone(), but something will need to be listening to MainClass to get that notification.
Here is a pattern I always use with my AsyncTask subclasses:
public class GetDataRemoteTask extends AsyncTask<String, Void, Data> {
private static final String TAG = "GetDataRemoteTask ";
private WeakReference<GetDataResultListener> mListenerRef;
private Exception mExc;
#Override
protected Data doInBackground(String... params) {
Data result = null;
try {
result = mService.getData(params[0], params[1], params[2]);
} catch (Exception e) {
Log.e(TAG, "Error occurred getting data", e);
mExc = e;
}
return result;
}
#Override
protected void onPostExecute(Data result) {
if (mListenerRef != null) {
GetDataResultListener listener = mListenerRef.get();
if (listener != null) {
if (mExc == null) {
listener.dataReceived(result);
} else {
listener.dataException(mExc);
}
}
}
}
public void setGetDataResultListener(GetDataResultListener listener) {
if (listener == null) {
this.mListenerRef = null;
} else {
this.mListenerRef = new WeakReference<GetDataResultListener >(listener);
}
}
public static interface GetDataResultListener {
public void dataReceived(Data data);
public void dataException(Exception exc);
}
}
So to start off, here I have an interface, like you do, for connecting to the AsyncTask. But I don't wrap my AsyncTask with an implementation, I expect that I will have an Activity or a Fragment that will implement this interface. (That's why I use a WeakReference; if the Activity finishes, my AsyncTask won't keep holding on to the Activity. But that also means I can't use an anonymous class listener unless the client holds the reference for it.)
My client code will look like this:
GetDataRemoteTask task = new GetDataRemoteTask();
task.setListener(this);
task.execute(param1, param2, param3);
I also have a way to find out if there was an exception that occurred in the background task. Any background exceptions should always be reported to the client, which can decide how best to deal with the exception - for example pop up a dialog for the user, so they know the request failed.
I think that a big drawback of AsyncTask is that it doesn't have more structure around handling exceptions that occur in the background thread.
My task holds a reference to the exception, but I have also used Pair<Data, Exception> as a type parameter for return result so I don't need the exception property.
Using this pattern has helped me avoid some typical problems that occur when coding AsyncTask subclasses.
I am working on a project that includes communication between computer application and embedded devices over serial port in Master-Slave mode.
The application will serve as Master to multiple embedded devices working as Slaves.
The communication part is almost complete. But now, I am refactoring it as an API.
So, it can be used over multiple projects or by many developers with very less configurations.
I am not very good in API design, even it's the first time, I am creating an API.
Now, I am stuck on following issue:
Consider this scenario:
/*
* API Part
*/
public abstract class AbstractSlave {
// Some fields, constructor and other methods.
final void handle(Request request, Response response) {
// Some operations before starting worker thread.
SlaveWorker worker = new SlaveWorker(request, response);
worker.start();
}
}
public class SlaveWorker extends Thread {
// Constructor
#Override
public final void run() {
work(request, response);
}
public void work(Request request, Response response) {
}
}
AbstractSlave class starts a worker thread to work upon the request and response, so that long-running operations cannot cause the loss of upcoming responses from slaves.
Now, here is the "API usage part":
/*
* API Usage Part
*/
public class Slave extends AbstractSlave {
// Constructor
}
public class MyWorker extends SlaveWorker {
// Constructor
#Override
public void work(Request request, Response response) {
super.work(request, response);
// My work to be done upon request and response.
}
}
But as we can see, AbstractSlave creates SlaveWorker instances.
So, SlaveWorker work() method will be called, instead of MyWorker.
How to make AbstractSlave class to call MyWorker work() method?
NOTE:
As it's an API design, AbstractSlave would not know, there is a MyWorker class. So, MyWorker instances cannot be created directly in place of SlaveWorker.
handle() method of AbstractSlave can/meant not be overridden, because there are some operations, that need to be performed before starting worker thread.
I think the key point would be to let the client of your API create the instance of SlaveWorker (or any subclass), so that he can customize the work() method.
IMO you should provide a Worker interface in your API (interface is less constraining than an abstract class):
public interface Worker {
public void work(Request request, Response response);
}
And AbstractSlave's method should be like:
public abstract class AbstractSlave {
private final Worker worker;
public AbstractSlave(Worker worker) {
this.worker = worker;
}
final void handle(final Request request, final Response response)
// Some operations before starting worker thread.
Thread t = new Thread() {
public void run() {
worker.work(request, response);
}
};
t.start();
}
}
There are different ways to do this, but one way is to add a configureJob method to your AbstractSlaveand use this to tell your AbstractSlave class about MyWorker.
public class SlaveManager {
private Class workerClass = SlaveWorker.class;
public void configureJob(Class clazz){
workerClass = clazz;
}
final void handle(Request request, Response response) {
// Some operations before starting worker thread.
Worker worker = workerClass.newInstance();
worker.start(request, response);
}
}
public interface Worker {
public void work(Request request, Response response);
}
In your main method, just call SlaveManager::configureJob(MyWorker.class) before you call SlaveManager::handle().
Now, I've kept things simple above by using Object.newInstance() to create the Worker, but this is not a recommended general practice. It's more customary to use a WorkerFactory instead, but I didn't want to introduce a new class and a new design pattern in case you were unfamiliar with the Factory Pattern.
say I want to perform an Http request from the server, this process takes time.
now because of this, the http request needs to be run on a different thread (AsyncTask, Runnable, etc.)
but sometimes I just need the response when I ask for it, in order to update the UI
using Thread.sleep in a loop to wait for the response is not good performance wise
example: I want the user's name, I ask the server for it, and I have to wait for it
now the activity calls the UserManager that calls the serverHandler that performs the operation and returns the result back
maybe an event system is in order, but I'm not sure how to do this in my scenerio
and quite frankly I am really confused on this issue
please help someone?
This can most definitely be done w/ AsyncTask... Handle the network request in doInBackground() and once doInBackground() is finished, onPostExecute() is triggered on the UI thread and that's where you can execute any code that will update UI elements.
If you need something a bit more generic and re-usable, you would probably want to implement a callback... I'll refer to the UI thread as the client and the AsyncTask as the server.
Create a new interface and create some method stubs.
public interface MyEventListener {
public void onEventCompleted();
public void onEventFailed();
}
Have your client pass instance of MyEventListener to the server. A typical way of doing this is to have your client implement the interface (MyEventListener) and pass itself to the server.
public class MyActivity implement MyEventListener {
public void startEvent() {
new MyAsyncTask(this).execute();
}
#Override
public void onEventCompleted() {
// TODO
}
#Override
public void onEventFailed() {
// TODO
}
}
On the onPostExecute of the server, check if the callback is null and call the appropriate method.
public class MyAsyncTask extends AsyncTask<Void, Void, Void> {
private MyEventListener callback;
public MyAsyncTask(MyEventListener cb) {
callback = cb;
}
[...]
#Override
protected void onPostExecute(Void aVoid) {
if(callback != null) {
callback.onEventCompleted();
}
}
}
You can read more about callbacks here: http://www.javaworld.com/javaworld/javatips/jw-javatip10.html