Reputation: 1793
I am implementing a client in android with retrofit. As i am using asynchronous requests, the client handles every request in a separate thread and then, i get the answer in a callback.
it looks something like this:
public void request(){
ThisService client = ServiceGenerator.createService(ThisService.class,baseUrl);
client.request(new Callback<Answer>() {
@Override
public void success(LoginAnswer answer, Response response) {
}
@Override
public void failure(RetrofitError error) {
}
});
}
What i need to do is , after the callback, change some UI setting, so what i did is to implement static methods in my activity:
public static void changeUI(){}
so that in the callback i can do something like:
public void request(){
ThisService client = ServiceGenerator.createService(ThisService.class,baseUrl);
client.request(new Callback<Answer>() {
@Override
public void success(LoginAnswer answer, Response response) {
Activity.changeUI();
}
@Override
public void failure(RetrofitError error) {
}
});
}
The problem is that that way of doing thigs is taking me to define a lot of static variables and methods for Activity(from static methods i can only call other static methods or access static variables). So for example, if from changeUI(), i want to call another Activity method, it has to be static, and so on.
If for example i want to finish the activity, i cannot call finish() becasuse that is not static.
I guess what i am trying to ask is: whats the best way to avoid this?
Every example i saw online, they implemented everything inside the sucess method, but it doesn't seem "clean" to me.
I was thinking something like a singleton pattern, where i can call a getInstance(),a static method that returns a copy of the activity and then,define non static method for UI changes.
Upvotes: 0
Views: 2632
Reputation: 3444
I like to handle these kinds of situations by defining a custom callback interface in my networking class, then send the message directly to whoever needs it. So for example, let's say you have a class called YourCallbackClass
that does some network operations. We'll define it like this:
public class YourCallbackClass {
YourNetworkCallbacks callback;
public YourCallbackClass(YourNetworkCallbacks callback) {
this.callback = callback;
}
public void networkMethod() {
String message = "This came from YourCallbackClass";
callback.networkCallback(message);
}
public interface YourNetworkCallbacks {
public void networkCallback(String message);
}
}
In this class, we define a public interface called YourNetworkCallbacks
which has a single method. This method will be used to send the result of our network operation back to the calling class. Our network method is just a dummy method defined as networkMethod()
. It simply produces a String which we send to our calling class.
So to get this String to another class, we have to have our calling class implement the public interface YourNetworkCallbacks
. So the top of our Activity that wants the network operation results would look something like this:
public class MainActivity extends AppCompatActivity implements YourCallbackClass.YourNetworkCallbacks {
...
...
Now all we have to do is actually implement the callback method that we defined in YourNetworkCallbacks
. So in MainActivity, we simply put:
public void networkCallback(String message) {
Log.d("NETWORK CALLBACK", "A message from YourCallbackClass: "+message);
}
And this implementation of our callback is now ready to receive messages. Now all we have to do is actually tell YourCallbackClass who is listening to our callbacks so it knows where to route the messages. We do this by passing in an instance of a listener, which is just any class that implements the callbacks. In this case, our MainActivity implements the callbacks by definition, so we can just send this
in when creating our instance of YourCallbackClass. So we would do:
YourCallbackClass callbackClass = new YourCallbackClass(this);
You'll see in YourCallbackClass, we take this listener that is passed in (which is just an instance of our Activity itself, which implements the callback) and we assign the reference to our own local callback variable. What this does is allow us to now send messages to the callback reference, which is really the reference to the callback in MainActivity. This effectively let's us communicate directly with MainActivity!
So now to send messages back to MainActivity, we simply do:
public void networkMethod() {
String message = "This came from YourCallbackClass";
callback.networkCallback(message);
}
The way you would implement this for your own project, is you would have the callbacks from your networking operations make this call to your own custom callbacks, which are implemented in whatever Activity/Class you want to get the information.
It's all very confusing at first, but once you get the hang of this, you quickly realize what a powerful tool callbacks are when dealing with asynchronous operations!
Hope this answers your question!
EDIT IN RESPONSE TO COMMENTS: OK, so let's talk about how you would implement this solution in your own project. You obviously have some class that is doing your network operations, and you mentioned you are getting the network results in a callback, right?
So your network operations class is your version of "YourCallbackClass." So in your network operations class, define the public interface and add a method called "sendNetworkResults()" or whatever you want to the interface definition. Also in your network operations class, you'll need to create a private member that is an instance of your interface. So in your network operations class, you should have the interface defined, and a private member which is an instance of your callbacks interface (in the example above, you see this as "YourNetworkCallbacks callback;").
Now in the Activity that wants your network results, have the Activity class implement your interface that you defined in your network operation class. So you need to add "implements" to the class definition, and you need to actually implement the sendNetworkResults()
method that you defined in the interface.
Now your Activity is all set up to receive the callbacks, and your network operations class is all set up to send the callbacks. The only thing left to do is connect the two to complete the bridge. So we do this by assigning an instance of your Activity to the callback member you created in your network operations class. In my example above, this is the YourNetworkCallbacks callback;
member. You can either do this by passing in the Activity to the network operation constructor (the way I did it in the example). Or you could create a setter method in your network operation class like setNetworkClassListener(YourNetworkCallbacks callback);
Once you make this assignment, you just send the messages to this callback member, and it automatically sends the result to the method you implemented in your Activity. So how do you do this?
You mentioned you're getting a callback for your network results. So when that callback comes in, you simply pass the relevant information on to your Activity by calling the method you defined in your interface, on the callback member we assigned. So it would be something like this:
//This is the callback that gets called when your network results come in
public void yourNetworkOperationCallback(String someValue) {
/**
* Now we take the String result that returned from the network callback
*and we pass it on to the Activity by sending it into our interface method
*using the callback reference we assigned. Here, "callback" is a member
* we defined for this class, and we assigned it the value of our Activity
* instance.
**/
callback.sendNetworkResults(someValue);
}
Remember we assigned the member callback
to the value of our Activity, which implements our interface. So we are essentially saying that the Activity is an instance of our callback, and we're just copying the reference to our local callback variable. So now when we call the sendNetworkResults()
method, it goes to the implementation we referenced, which is our Activity.
So your network callback should look something like this:
public void request(){
ThisService client = ServiceGenerator.createService(ThisService.class,baseUrl);
client.request(new Callback<Answer>() {
@Override
public void success(LoginAnswer answer, Response response) {
//We're passing these values directly to Activity
callback.sendNetworkResult(answer, response);
}
@Override
public void failure(RetrofitError error) {
}
});
}
Then in your Activity, you have the sendNetworkResults()
method implemented, so it looks something like this:
public void sendNetworkResults(LoginAnswer answer, Response response) {
//This is implemented in your Activity. So now just update your Activity UI
//with the answer and response values!
}
And now you have the answer
and response
values in your Activity! Only thing left to do is use them to update your UI.
Hope this all makes sense. I know it's super confusing :)
Upvotes: 4
Reputation: 1763
You could use the LocalBroadcastManager
declare a receiver inside your ui element
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// do whatever you ui needs to update
}
}
};
and listen for any broadcasts from your ui element by
@Override
protected void onStart() {
super.onStart();
final IntentFilter filter = new IntentFilter("nameOfYourFilterAction");
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, filter);
}
@Override
protected void onStop() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
super.onStop();
}
from your task you just simply send a new Intent object
final Intent broadcast = new Intent("nameOfYourFilterAction");
broadcast.put(<any extras>);
LocalBroadcastManager.getInstance(<some context>).sendBroadcast(broadcast);
Upvotes: 0