在SDK中授予对Activity UI的控制权

问题描述 投票:1回答:1

目前我们正在制作一个包含Activity的Android库。我们希望控制活动的确切流程和状态,但是为实现库控件的用户提供UI的外观。同时,我们希望暴露最少量的内部类。

SDK用户可以决定放置视图的位置,大小,颜色;我们决定在onClicks上发生了什么,并提供TextViews的文本。

该活动使用了Model-View-Intent模式,因此我们希望公开不可变状态。如果没有可调整的UI,则Activity及其所有类都是内部的。通过可调节的UI,更多的课程必须公开。这增加了更新更改的风险并暴露了我们的逻辑。

为了公开UI,我们想到了几个解决方案:

  • 对调用onCreate()的活动进行静态回调,因此可以设置setContentView(),并在每次状态更改时调用render(state: State)。我们的课程按照我们的意愿进行了屏蔽,但是使用静态课程是值得怀疑的。
  • 使活动打开,因此sdk用户可以将其子类化。这意味着活动使用的每个类都必须从内部更改为公共。实际应该是内部的类将通过使用ProGuard对它们进行模糊处理来隐藏。
  • Intent中传递一个函数是最好的,这对我的知识是不可能的。
  • 通过POJO我们定义了背景颜色等参数,这是对sdk用户的最大限制,并没有考虑。

哪种解决方案最好?还有另一种方法,而不是我们想到的方法吗?

android kotlin aar
1个回答
1
投票

SDK用户可以决定放置视图的位置,大小,颜色;我们决定在onClicks上发生了什么,并提供TextViews的文本。

我这样想是这样的:

  • 您的消费者会收到StateViewGroupActions对象,我稍后会解释。
  • 基于State,消费者需要创建多个视图并按照他们的意愿将它们放在提供的ViewGroup中。
  • 消费者还需要使用一些Actions.register*Button方法在上面注册。
  • 上述逻辑在一个回调方法中执行。完成所述方法后,SDK将验证是否正确(所有必需操作都分配了可点击的视图)并继续。

现在,如何将此回调方法传递给恶魔SDK?

1.

在Intent中传递一个函数是最好的

这实际上可以相对容易地实现(并且,IMO,一些严重的缺点)。

在您的SDK中创建一个静态Map<Key, Callback> sCallbacks。当您的消费者使用您的API注册回调时,您将为其生成查找键并将其存储在地图中。您可以将密钥作为Intent额外传递。打开SDK活动后,它可以使用其意图中的密钥查找回调。

关键可以是StringUUID或任何符合您需求的东西,可以置于意图之内。

优点:

  • 它的实现和使用看似简单。
  • 消费者可以只使用一个文件中的SDK。所有的调用代码都在一个地方。

缺点:

  • 你没有负责创建回调的地方。消费者可能会将其创建为Activity中的匿名类,从而导致内存泄漏。
  • 当进程死亡时,您将丢失回调映射。如果应用程序在SDK活动中被终止,则需要在重新启动应用程序时正常处理它。
  • 变量不会在多个进程之间共享。如果您的SDK活动和调用代码不在同一个过程中,则您的SDK活动将无法找到回调。请记住,消费者可以自由地更改其活动流程,甚至可以覆盖您自己的活动流程。

调用点看起来像startSdk(context) { state, parent, actions -> /* ... */ }

对于消费者而言,这是迄今为止最舒适的方法,但是一旦您离开典型的消费者设置区域,这些弱点就开始出现。

2.

使活动打开,因此sdk用户可以将其子类化。

正如您所解释的那样,如果不妥协,这是不可能的。

优点:?

缺点:

  • 消费者需要注册他们的子类并在AndroidManifest.xml中取消注册您原来的SDK活动。我假设清单合并已启用。这是一种痛苦,因为我经常忘记看这里。
  • 消费者可以轻松访问您的活动,并可随意打破它。
  • 除非您的文档是原始的,否则消费者将很难确定您的活动中要覆盖的内容。

调用点看起来像startSdk<MySdkActivity>(context)

作为消费者,我真的不明白这个选项的好处。我失去了#1的好处而没有获得任何回报。作为开发者,我不能批准这种“让消费者处理它”的态度。他们会破坏事情,你会得到错误报告,你最终将不得不处理它。

3.

在这里,我将尝试扩展评论中首先提到的想法。

回调将是SDK定义的抽象类。它将使用如下:

  • 使用者扩展了这个类并定义了回调体。该类需要一个空构造函数并且是静态的。通常,它将在自己的文件中定义。
  • 类名称会在您的SDK活动中传递。
  • 您的SDK活动反射性地创建回调的实例。

回调类可以有多个方法,一个可以设置菜单,一个可以只设置视图层次结构,一个可以将整个活动作为参数。消费者会选择他们需要的那个。同样,如果有多个选项,则需要将其记录好。

优点:

  • 您将回调与调用站点(调用SDK的位置)分开。这很好,因为回调是在您的活动中执行的,与调用代码完全分开。
  • 因此,您无法泄漏调用活动。
  • 消费者不需要触摸AndroidManifest.xml。这很棒,因为注册回调与Android无关。清单主要用于系统与之交互的事物。
  • 在进程死亡后很容易重新创建回调。它没有构造函数参数,它是无状态的。
  • 它适用于多个流程。如果消费者有任何机会需要跨流程进行沟通,他们就会负责实现这一目标。你的SDK并没有像第二种情况那样使它变得不可能。
  • 你得保持你的课程internal

缺点:

  • 您必须捆绑一个proguard规则,以保持每个类的空构造函数扩展抽象回调类。你还需要保留他们的班级名称。

我假设您将隐藏作为实现细节传递的意图,因此入口点看起来像startSdk<MyCallback>(context)

我喜欢这个,因为它将所有可能的责任从消费者转移到SDK开发人员。您使消费者难以使用API​​错误。您可以保护消费者免受潜在错误。

现在回到第一段。只要消费者能够掌握上下文(ViewGroup.getContext()),他们就能够访问活动和应用程序(在该过程中)。如果调用活动和SDK活动都在同一个进程中,那么消费者甚至可以访问他们准备好的Dagger组件。但他们不会以意想不到的方式覆盖您的活动方法。

© www.soinside.com 2019 - 2024. All rights reserved.