I'm designing SDK for Android.
As a web developer, I'm very used to and comfortable with callbacks, and as the SDK will include many async operations, I'm not sure what is the most common or "best" way to implement such a behavior on Android (or Java in general).
I've come up with a couple of options:
1) Listener interface - the developer that will use the SDK will implement a listener interface that will include all the callbacks, for example:
interface ISDKListener {
public void onA();
public void onB();
}
class SDK {
private ISDKListener _listener;
public SDK(ISDKListener listener) {
_listener = listener
}
public void a() {
// Do stuff
_listener.onA();
}
public void b() {
// Do stuff
_listener.onB();
}
}
As a web developer, using JS that looks a bit too much for me, "forcing" the user (developer) to implement all the listeners in advance, when he might no even use all of them.
2) Single listeners setters
Basically set a listener to each async method. For example:
interface ISDKCallback {
public void onComplete();
}
class SDK {
private ISDKCallback _aCb;
private ISDKCallback _bCb;
public void setAListener(ISDKCallback aCb) {
_aCb = aCb
}
public void a() {
// Do stuff
if (_aCb != null) _aCb.onComplete();
}
public void setBListener(ISDKCallback bCb) {
_bCb = bCb
}
public void b() {
// Do stuff
if (_bCb != null) _bCb.onComplete();
}
}
3) Same as #2, but separate success and errors:
interface ISDKCallback {
public void onSuccess();
public void onError(Exception e);
}
class SDK {
private ISDKCallback _aCb;
public void setAListener(ISDKCallback aCb) {
_aCb = aCb
}
public void a() {
try {
// Do stuff
if (_aCb != null) _aCb.onSuccess();
} catch (Exception e) {
if (_aCb != null) _aCb.onError(e);
}
}
}
4) Combining #1 and #3 - a complete listener with all the callbacks, but each callback will be 2 callbacks, one for success and one for errors:
interface ISDKListener {
public void onA();
public void onAError(Exception e);
public void onB();
public void onBError(Exception e);
}
class SDK {
private ISDKListener _listener;
public SDK(ISDKListener listener) {
_listener = listener
}
public void a() {
try {
// Do stuff
_listener.onA();
} catch (Exception e) {
_listener.onAError(e);
}
}
public void b() {
try {
// Do stuff
_listener.onB();
} catch (Exception e) {
_listener.onBError(e);
}
}
}
The 3rd one seems most "natural" for me, due to the separation between success and error (like the promise then and catch on JS) and setting each callback separately. Actually the most natural to me was to pass the callback when I call the method, but I did not found such implementation anywhere in Java as far as I've searched.
Which one is the most common and will be the most "natural" to most Android/Java developers? Are there any other suggestions for implementing callbacks in that platform?
EDIT:
To clarify, the callbacks are either for HTTP responses to HTTP requests or BLE communication, for example method a will send some request over BLE to a BLE peripheral, and the callback for a will be called when the peripheral returned a response (the mobile and peripheral are implementing a client-server protocol over BLE)
I'm not the biggest expert out there but if you're asking which is the most common implementation I would say numer 1. You can take a look at a lot of libraries out there, I used a lot of them myself and this is what I found to be the most used solution.
One good example would be the usage of ExoPlayer (I'm choosing it just because I'm working on it at the moment).
As you can see the activity includes an instance of the player + all the objects it needs like the BandwidthMeter and implements ExoPlayer.EventListener inheriting all the callbacks like onPlayerStateChanged.
Even the Android API itself makes use of this pattern, maybe too much. But this is another topic I guess. A lot of people finds this approach a bit confusing because you end up with a callback hell and I'm with them.
Edit
Another good example of a different approach can be found in the Google API Client (which suits your situation better).
As you can see you connect to the Client with two listener, and you have another optional listener for errors with a different interface and an additional callback.
Conclusion
I guess in the end it really depends on you: solution 1 and 2 both look good to me. Number 3 will work too but I'm not too familiar with it, maybe this is a sign that it's not a widely used pattern in Android Development.
In general, callbacks or listeners interfaces are a valid approach, but I would choose Android LiveData. It's an observational data holder which wraps your data and let others listen to your changes. In your case, I would expose LiveData with some kind of model, and the users of your sdk would then observe your return value of type LiveData for future changes in the data. Thus the users of your sdk won't have to implement nothing.
I've just wrote a blog post where I go over callbacks (as well as event bus and LiveData), describing the scenarios in which we should use one over another and the pros and cons of using one rather than the other. I think it may be useful to you:
When and why to use LiveData
Related
I would like to use a Java Library inside of my Kotlin Android App, but I am relatively new to Kotlin and need some advice. The Library basically looks like this:
public interface Listener{
void onResult(Result res)
}
public class Client{
public Client(){}
public void setListener(Listener l){}
public void start(){} // Starts Thread(s) (so it's non-blocking), does some server calls, computes result, calls listener.onResult(res) after computation is finished.
public void cancel(){}
}
Yes, I know, I could just call the functions directly and use it like in java, but is that the Kotlin way?
I read, doing a similar task (using an asynchronous function, which takes a callback parameter) would be done by wrapping it in a coroutine/suspend function structure.
But I don't know howto adapt this for my Problem(?) or is it the wrong approach?
If you want to make this into a nice easy Kotlin suspending function, it would be like this:
suspend fun doTheThing() : Result {
val c = Client()
try {
//suspend until the listener fires or we're cancelled
return suspendCancellableCoroutine {
cont ->
c.setListener {
result -> cont.resume(result)
}
c.start()
}
} catch (e: Exception) {
// If someone cancels the parent job, our job will complete exceptionally
// before the client is done. Cancel the client since we don't need it
// anymore
c.cancel()
throw e
}
}
I don't see a way in your interface for the client to indicate failure. If that's part of Result then you probably want to turn that into an exception in the listener
I am having serious difficulties to understand how can I make some AsyncTask children, declared and instantiated in the Main Thread, to await for a Service child instance to reach some specific state.
As code examples here is the relevant part for Service; this code does what expected: receives the JSON response and holds it.
public class MyService extends Service {
private boolean received = false;
private string url = "http://someserver.mine/get-data-in-json-format";
// [...]
#Override
public void onCreate() {
doHttpJsonQuery();
}
public boolean responseReceived() {
return this.received;
}
public List<MyModel> getResponseAsObject() {
if (!this.received) return new ArrayList<MyModel>;
// Many code lines that convert the data into a list.
// [...]
return the_list;
}
// [...]
private void doHttpJsonQuery() {
OkHttpClient client = new OkHttpClient.Builder()
.build();
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
call.cancel();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
//...and some code to hold data as JSONArray
//[...]
}
});
this.received = true;
}
}
This Service works; fine. Then, from another class (which purpose will be to handle persistence inserting the received data in a local Room Database), I try to do the following (here's where my mind is blown):
public class DataRepository {
private MyRoomDatabase db;
private MyModelDao mModelDao;
// I'm skipping irrelevant code on purpose
// [...]
public DataRepository(Application application) {
db = MyRoomDatabase.getDatabase(application);
mModelDao = db.myModelDao();
// [...]
// Here I instance a subclass of ContextWrapper(i named it RemoteDataSource) which
// responsability will be handling different Services for making HTTP operations
mRemoteDataSource = new RemoteDataSource(application.getApplicationContext());
// It holds a reference to MyService. It has some public methods, like this one, to
// control the referenced Service from outside with some encaspsulation
mRemoteDataSource.startMyService();
// Instantiating a private nested class...
PopulateDbAsync mPopulateDbAsync = new PopulateDbAsync(db);
mPopulateDbAsync.doInBackground();
}
// [...]
// Here is the failing code
private class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
PopulateDbAsync(MyRoomDatabase db) {}
#Override
protected Void doInBackground(final Void... params) {
MyService mService = mRemoteDataSource.getMyService();
if (mService == null) {
// This doesn't happen at all right now...
Log.e("MY_ERROR","DataRepository.PopulateDbAsync --> MyService from RemoteDataSource is NULL!!!!");
}
List<MyModel> the_list = mService.getResponseAsObject();
if (the_list == null) {
// HERE! I obtain the NullReferenceException here.
// I am confused about how would I avoid this flaw in my code
Log.e("MY_ERROR", "DataRepository.PopulateDbAsync --> error: response isn't ready yet.");
}
for (MyModel i_model : the_list) {
Log.d("MY_LOG", "DataRepository.PopulateDbAsync --> Inserting data in local DB...");
mModelDao.insert(i_model);
}
return null;
}
}
}
Summarizing: my problem is that I will always get NullReferenceException in this line:
for (MyModel i_model : the_list) {
I am not familiar with multithreading, asyncronous operations and concurrent execution. I have been reading, for two weeks, lots of different documents on the Internet both from Android Official Website and from other websites as well, trying to figure it out... "AsyncTask is not good to perform this kind of operations"... so, what infrastructure should I implement, I have been wondering... should I use Handlers, Threads, Messengers, or what? The more I read, the more confused I get. It's like I have an Analysis Paralysis issue...
Most of the examples I find out there provide too verbose code examples on how to implement multithreading and concurrent execution; while I read them and try to figure out how to implement those structures in my code, I just get stuck; also, with so many classes to choose, I get even more confused...
Due to the HTTP call will need to be performed asyncronously (and response time will not always be the same), I am trying to figure out how to make the piece of code that throws the NullReferenceException "wait" for MyService to complete it's job before starting it's execution; while loops will not work due to it would break Main Thread's lifecycle. "Knowing" if the Service completed it's task or not would be as simple as using the boolean method responseReceived. The big idea is, every time new data is obtained through HTTP, updating the RoomDatabase with it, and, meanwhile, MainActivity would be showing the current local data (if any, or an empty list if there's nothing yet).
So, when I get it, I will understand how to refactor the whole code structure properly to start adding more Service child instances into my RemoteDataSource class, which I created with the idea of having all Service childs that will use OkHttp to perform HTTP communications, wrapped together in a single class for better organization.
What would be the proper way to achieve what I am looking for about this? Would someone be able to provide some short example explaining the code structure I will need for something like this? Examples with empty blocks containing comments like "code to execute when ready here" would be great so I can figure it out.
The question exposed here is related with the same project that made me post this other question some weeks ago; I have been reading here and there, performing some trial-and-error and correcting some code issues here-and-there since then; however, I am making a different question here; finding an answer for this would probably be the first step towards figuring out an answer to the other question as well.
URL References to documentation I have been reading
Some of the documentation I have been reading (but not limited to):
AsyncTask class documentation
Handler class documentation
Basics on Multithreading
Introduction to background processing in Android - Tutorial
Thread With Handlers - Android Example
Messenger class documentation
Well problem is with your application logic as follows,
If you are using AsyncTask that is obviously a separate thread from the main thread. But syncing to your database after retrieving data via HTTP call is a process which has a sequence ( Call through HTTP and retreive -> then persist to database ), it cannot perform asynchronously. So when you call,
List<MyModel> the_list = mService.getResponseAsObject();
this call happens in a particular thread and the program flow is in a different thread.
Since these are asynchronous tasks, they work asynchronously. which means you will never know which one will execute first and which one is next. But as per your logic,
if (the_list == null) {
this part essentially need the_list to be initialized to run. But the problem is at that point, service thread has not finished his work to perform your next logic. so its obvious breaking.
Better if you can re-design this so that you wait for the HTTP request to complete and then persist to database. Because suppose if your HTTP request complets first but still it returns you null or whatever not-desired output. So in that case you need to handle it in your logic.
OK so let me tell you a quick workaround.
Lets use just one thread instead of different threads. So consider changing following line
private class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
to
private class PopulateDbAsync
then you will get an error with
#Override
protected Void doInBackground(final Void... params) {
since we no longer extend AsyncTask class.
so change it as follows, by removing #Override
public Void doInBackground(final Void... params) {
This should fix the stated problem here.
I found a solution: creating custom listeners.
Steps to create a custom listener
1. Define an interface as an event contract with methods that define
events and arguments which are relevant event data.
2. Setup a listener member variable and setter in the child object which can be assigned an implementation of the interface.
3. Owner passes in a listener which implements the interface and handles the events from the child object.
4. Trigger events on the defined listener when the object wants to communicate events to it's owner
I got the NullReferenceException because MyService didn't finish it's job yet. So, first I create the listener's structure within MyService class like this (steps 1 and 2):
private MyServiceListener listener;
public interface MyServiceListener {
public void onDataDownloaded();
}
public void setMyServiceListener(MyServiceListener listener) {
this.listener = listener;
}
And, within the HTTP request's callback (step 4):
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
//...and some code to hold data as JSONArray
//[...]
// XXX Trigger the custom event
if (listener != null) {
listener.onDataDownloaded();
}
}
Now, I just can wrap the code that triggered the NullReferenceException within the custom listener like this (step 3):
// Within DataRepository class
mService.setMyServiceListener(new MyService.MyServiceListener) {
#Override
public void onDataDownloaded() {
List<MyModel> the_list = mService.getResponseAsObject();
if (the_list == null) {
// HERE! I obtainED the NullReferenceException here.
Log.e("MY_ERROR", "DataRepository.PopulateDbAsync --> error: response isn't ready yet.");
}
for (MyModel i_model : the_list) {
Log.d("MY_LOG", "DataRepository.PopulateDbAsync --> Inserting data in local DB...");
mModelDao.insert(i_model);
}
return null;
}
}
Actually, the real implementation required to nest this code example into another custom listener following similar steps; but this worked for me.
I'm starting with GWT and learning Event bus concepts now. I find this solution extremely complicated. So I tried to simplify it by writing prototype by myself to see all problems.
At first I will write about my understanding of event bus (that can be completely wrong).
We have events like this
public class FooEvent extends GwtEvent<FooHandler> {
public static Type<FooHandler> TYPE = new Type<FooHandler>(); //as event type integer ID
//for.. hm.. probably some inner use in Event Bus
#Override public Type<FooHandler> getAssociatedType() {
return TYPE;
}
//for handling
#Override protected void dispatch(FooHandler handler) {
handler.someMethod(this);
}
}
handler interface,
public interface FooHandler extends EventHandler {
void someMethod(FooEvent event);
}
usage
eventBus.addHandler(FooEvent.TYPE, new FooHandler() {
#Override
public void someMethod(FooEvent event) {
//bla-bla
}
});
eventBus.fireEvent(new FooEvent());
Thats it. And now my prototype.
//replaced GwtEvent
interface UniGwtEvent {
}
//than, event pretty simple
public class FooEvent extends UniGwtEvent {
}
//replaced GwtEventHandler. You should not create special handler class per event!
public interface UniEventHandler<T extends UniGwtEvent> {
void handle(T event);
}
//event bus prototype(in pseudocode)
class UniEventBus {
//map. keys getted from class. as I understand, it's possible from GWT 1.5 see http://code.google.com/p/google-web-toolkit/issues/detail?id=370
public <T extends UniGwtEvent> void addListener(Class<T> event, UniEventHandler<T> handler){
map.put(event.getName(), handler);
}
public void fireEvent(UniGwtEvent event){
if(map.contains(event.getClass().getName())){
map.get(event).handle(event);
}
}
}
usage
eventBus.addListener(FooEvent.class, new UniEventHandler<FooEvent>(){
#Override
public void handle(FooEvent event) {
bla-bla
}
});
eventBus.fireEvent(new FooEvent());
I think this solution is much better since you shouldn't make unnecessary Type manipulation and create Handler Class per event. I see only one disadvantage - you should specify generic type on handler creation. But I suppose there are many other disadvantages or ever issues that makes this solution impossible. What are they?
There is no obvious advantage to using your implementation. As I read it there are two differences between yours and GWT's EventBus:
Using Strings instead of Type objects to bind event handlers to event types. This is not a meaningful difference - there's no penalty to having more types in your application and I suspect that, at runtime, Strings will use slightly more resources than Types.
Dispatching events to the appropriate handlers directly instead of delegating to the event type. I prefer GWT's approach here because it affords flexibility in how events are dispatched. One might, for example, want handlers to implement two different methods that are invoked depending on the context of the event. Take the following (trivial) example:
public class ExampleEvent extends GwtEvent<ExampleEvent.Handler> {
public interface Handler extends EventHandler {
void onExample(Integer id);
void onExample(String name);
}
private final Integer id;
private final String name;
public ExampleEvent(Integer id) {
this.id = id;
this.name = null;
}
public ExampleEvent(String name) {
this.name = name;
this.id = null;
}
public void dispatch(Handler handler) {
if (name != null) {
handler.onExample(name);
} else {
handler.onExample(id);
}
}
}
In this case delegating dispatch to the event allows us to take an action that must be performed for every handler (determining whether the event contains an id or a name) without requiring that the test be performed in every individual event handler.
I recommend using GWT's EventBus implementation - it works and it is tested.
There are other event bus implementations out there that will do a good job. I recently created a very efficient event bus (Mbassador) that I have been using in production for a while now. It's hosted on github and you are invited to take a look.
https://github.com/bennidi/mbassador
Another option would be to use google guavas event bus but it lacks some useful features (which is why I implemented my own solution)
EDIT: I created a performance and feature comparison for a selection of available event bus implementations including Guava, MBassador and some more. The results are quite interesting. Check it out here
http://codeblock.engio.net/?p=37
I'm used to programming in C#, and one thing I miss about Java is that it doesn't seem to have C#'s nice built-in event handling capabilities:
// define event signature
public delegate void SomeEventHandler();
class SomeEventGenerator {
// define subscribable event property
public event SomeEventHandler SomeEvent;
protected void OnSomeEvent() {
if (SomeEvent != null) {
SomeEvent();
}
}
}
class SomeEventClient {
public SomeEventClient(SomeEventGenerator eg) {
// subscribe
eg.SomeEvent += new SomeEventHandler(eg_SomeEvent);
// do some stuff
// unsubscribe
eg.SomeEvent -= new SomeEventHandler(eg_SomeEvent);
}
private void eg_SomeEvent() {
// handle event
}
}
What's the best way to get something similar and lightweight in Java/Android which has the ability to subscribe/unsubscribe multiple event clients and call all subscribed clients at once?
You would want to look into the concept of listeners in java. I found a very good article called "C# from a Java developers perspective" that you might want to check out.
http://www.25hoursaday.com/CsharpVsJava.html
I am trying to design a Java system that is simliar to the concept of c# delegates.
Here is the basic functionality i wish to achieve:
public class mainform
{
public delegate onProcessCompleted
//......
processInformation()
{
onProcessCompleted(this);
}
//......
}
//PLUGIN
public class PluginA
{
public PluginA()
{
//somehow subscribe to mainforms onProcessingCompleted with callback myCallback()
}
public void myCallback(object sender)
{
}
}
I have read through this site: http://www.javaworld.com/javaqa/2000-08/01-qa-0804-events.html?page=1
They make reference to implementing the whole 'subscription list' manually. But the code is not a complete example, and I'm so used to c# that I'm having trouble grasping how I could do it in java.
Does anyone have a working examle of this that I could see?
thanks
Stephanie
In Java you don't have function delegates (effectively method references); you have to pass an entire class implementing a certain interface. E.g.
class Producer {
// allow a third party to plug in a listener
ProducerEventListener my_listener;
public void setEventListener(ProducerEventListener a_listener) {
my_listener = a_listener;
}
public void foo() {
...
// an event happened; notify the listener
if (my_listener != null) my_listener.onFooHappened(new FooEvent(...));
...
}
}
// Define events that listener should be able to react to
public interface ProducerEventListener {
void onFooHappened(FooEvent e);
void onBarOccured(BarEvent e);
// .. as many as logically needed; often only one
}
// Some silly listener reacting to events
class Consumer implements ProducerEventListener {
public void onFooHappened(FooEvent e) {
log.info("Got " + e.getAmount() + " of foo");
}
...
}
...
someProducer.setEventListener(new Consumer()); // attach an instance of listener
Often you have trivial listeners that you create via an anonymous classes in place:
someProducer.setEventListener(new ProducerEventListener(){
public void onFooHappened(FooEvent e) {
log.info("Got " + e.getAmount() + " of foo");
}
public void onBarOccured(BarEvent e) {} // ignore
});
If you want to allow many listeners per event (as e.g. GUI components do), you manage a list which you usually want to be synchronized, and have addWhateverListener and removeWhateverListener to manage it.
Yes, this is insanely cumbersome. Your eyes don't lie to you.