Java Android-在SDK中实现回调

Java Android-在SDK中实现回调,java,android,callback,sdk,Java,Android,Callback,Sdk,我正在为Android设计SDK。 作为一名web开发人员,我非常习惯并熟悉回调,由于SDK将包含许多异步操作,我不确定在Android(或Java)上实现这种行为的最常见或“最佳”方式是什么 我提出了几个选择: 1) 侦听器接口-将使用SDK的开发人员将实现一个侦听器接口,该接口将包括所有回调,例如: interface ISDKListener { public void onA(); public void onB(); } class SDK { priv

我正在为Android设计SDK。 作为一名web开发人员,我非常习惯并熟悉回调,由于SDK将包含许多异步操作,我不确定在Android(或Java)上实现这种行为的最常见或“最佳”方式是什么

我提出了几个选择:

1) 侦听器接口-将使用SDK的开发人员将实现一个侦听器接口,该接口将包括所有回调,例如:

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();
    }

}
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();
    }

}
作为一名web开发人员,使用JS对我来说有点过分,“强迫”用户(开发人员)提前实现所有侦听器,而他甚至可能不使用所有侦听器

2) 单侦听器设置器 基本上为每个异步方法设置一个侦听器。例如:

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();
    }

}
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) 与#2相同,但成功与错误分开:

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) 结合#1和#3-一个包含所有回调的完整侦听器,但每个回调将有两个回调,一个用于成功,一个用于错误:

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);
        }
    }

}

第三个对我来说似乎最“自然”,因为成功和错误是分开的(比如JS上的承诺
then
catch
),并且分别设置每个回调。实际上,对我来说最自然的方法是在调用该方法时传递回调,但我在Java中没有找到这样的实现

对于大多数Android/Java开发人员来说,哪一种最常见、最“自然”?在该平台上实现回调还有其他建议吗

编辑:


为了澄清,回调用于HTTP请求的HTTP响应或BLE通信,例如,方法
a
将通过BLE向BLE外围设备发送一些请求,并且当外围设备返回响应时,将调用
a
的回调(移动设备和外围设备正在通过BLE实现客户机-服务器协议)

我不是最大的专家,但如果你问哪一种是最常见的实现,我会说数字1。你可以看看很多库,我自己也使用了很多库,这是我发现最常用的解决方案

一个很好的例子是的用法(我选择它只是因为我现在正在研究它)

如您所见,该活动包括一个播放器实例+它需要的所有对象,如
带宽计
,并实现
ExoPlayer.EventListener
继承所有回调,如
onPlayerStateChanged

甚至安卓API本身也使用了这种模式,可能太多了。但我想这是另一个话题。很多人觉得这种方法有点混乱,因为你最终会遇到一个回调地狱,而我和他们在一起

编辑

另一个不同方法的好例子可以在中找到(这更适合您的情况)

正如您所看到的,您使用两个侦听器连接到客户机,并且您有另一个可选的错误侦听器,该侦听器具有不同的接口和额外的回调

结论


我想最终这真的取决于你:解决方案1和2在我看来都不错。第3个也可以,但我对它不太熟悉,也许这表明它在Android开发中不是一种广泛使用的模式。

一般来说,回调或侦听器接口是一种有效的方法,但我会选择Android LiveData。它是一种观察者Vantional data holder,它包装您的数据并让其他人聆听您的更改。在您的情况下,我将使用某种模型公开LiveData,然后您的sdk用户将观察您的LiveData类型返回值,以便将来对数据进行更改。因此,您的sdk用户不必什么都不实现

我刚刚写了一篇博客文章,介绍了回调(以及事件总线和LiveData),描述了我们应该使用一个回调而不是另一个回调的场景,以及使用一个回调而不是另一个回调的优缺点。我认为这可能对您有用:


“实际上,对我来说最自然的方法是在调用该方法时传递回调,但就我所搜索的而言,我在Java中的任何地方都找不到这样的实现”--这种模式在许多地方使用,例如
requestLocationUpdates()
上的
LocationManager
。“在该平台上实现回调还有其他建议吗?"--这完全取决于这些回调的具体性质。有RxJava/RxAndroid、
LiveData
、事件总线等。在我的例子中,回调要么是对HTTP请求的HTTP响应,要么是BLE通信,例如,方法
a
将通过BLE向BLE外围设备发送一些请求,
a
的回调将当外围设备返回响应时(移动设备和外围设备正在通过BLE实现客户机-服务器协议)将被调用。“在我的情况下,回调是对HTTP请求的HTTP响应”--像样的HTTP客户端API,如OkHttp,为您提供异步工作,因此您可能正在使用它们的回调机制,而不是自己的回调机制。OkHttp是为请求模式提供回调的另一个很好的例子。关于BLE,键是组件。如果服务是监视BLE连接和回调的对象从一个活动开始,事情会因为生命周期而变得混乱,比如.Rx、
LiveData
,或者事件总线都是更好的选择。