目前我们正在制作一个包含Activity
的Android库。我们希望控制活动的确切流程和状态,但是为实现库控件的用户提供UI的外观。同时,我们希望暴露最少量的内部类。
SDK用户可以决定放置视图的位置,大小,颜色;我们决定在onClicks上发生了什么,并提供TextViews的文本。
该活动使用了Model-View-Intent模式,因此我们希望公开不可变状态。如果没有可调整的UI,则Activity及其所有类都是内部的。通过可调节的UI,更多的课程必须公开。这增加了更新更改的风险并暴露了我们的逻辑。
为了公开UI,我们想到了几个解决方案:
onCreate()
的活动进行静态回调,因此可以设置setContentView()
,并在每次状态更改时调用render(state: State)
。我们的课程按照我们的意愿进行了屏蔽,但是使用静态课程是值得怀疑的。Intent
中传递一个函数是最好的,这对我的知识是不可能的。哪种解决方案最好?还有另一种方法,而不是我们想到的方法吗?
SDK用户可以决定放置视图的位置,大小,颜色;我们决定在onClicks上发生了什么,并提供TextViews的文本。
我这样想是这样的:
State
,ViewGroup
和Actions
对象,我稍后会解释。State
,消费者需要创建多个视图并按照他们的意愿将它们放在提供的ViewGroup
中。Actions.register*Button
方法在上面注册。现在,如何将此回调方法传递给恶魔SDK?
在Intent中传递一个函数是最好的
这实际上可以相对容易地实现(并且,IMO,一些严重的缺点)。
在您的SDK中创建一个静态Map<Key, Callback> sCallbacks
。当您的消费者使用您的API注册回调时,您将为其生成查找键并将其存储在地图中。您可以将密钥作为Intent
额外传递。打开SDK活动后,它可以使用其意图中的密钥查找回调。
关键可以是String
或UUID
或任何符合您需求的东西,可以置于意图之内。
优点:
缺点:
Activity
中的匿名类,从而导致内存泄漏。调用点看起来像startSdk(context) { state, parent, actions -> /* ... */ }
。
对于消费者而言,这是迄今为止最舒适的方法,但是一旦您离开典型的消费者设置区域,这些弱点就开始出现。
使活动打开,因此sdk用户可以将其子类化。
正如您所解释的那样,如果不妥协,这是不可能的。
优点:?
缺点:
AndroidManifest.xml
中取消注册您原来的SDK活动。我假设清单合并已启用。这是一种痛苦,因为我经常忘记看这里。调用点看起来像startSdk<MySdkActivity>(context)
。
作为消费者,我真的不明白这个选项的好处。我失去了#1的好处而没有获得任何回报。作为开发者,我不能批准这种“让消费者处理它”的态度。他们会破坏事情,你会得到错误报告,你最终将不得不处理它。
在这里,我将尝试扩展评论中首先提到的想法。
回调将是SDK定义的抽象类。它将使用如下:
回调类可以有多个方法,一个可以设置菜单,一个可以只设置视图层次结构,一个可以将整个活动作为参数。消费者会选择他们需要的那个。同样,如果有多个选项,则需要将其记录好。
优点:
AndroidManifest.xml
。这很棒,因为注册回调与Android无关。清单主要用于系统与之交互的事物。internal
。缺点:
我假设您将隐藏作为实现细节传递的意图,因此入口点看起来像startSdk<MyCallback>(context)
。
我喜欢这个,因为它将所有可能的责任从消费者转移到SDK开发人员。您使消费者难以使用API错误。您可以保护消费者免受潜在错误。
现在回到第一段。只要消费者能够掌握上下文(ViewGroup.getContext()
),他们就能够访问活动和应用程序(在该过程中)。如果调用活动和SDK活动都在同一个进程中,那么消费者甚至可以访问他们准备好的Dagger组件。但他们不会以意想不到的方式覆盖您的活动方法。