避免静态视图引用,但启用不同的活动来修改视图

Posted

技术标签:

【中文标题】避免静态视图引用,但启用不同的活动来修改视图【英文标题】:avoiding static view references but enabling a different activity to modify the views 【发布时间】:2019-09-26 16:53:32 【问题描述】:

我正在使用 UsbSerial (com.github.felHR85:UsbSerial:4.5) 将串行数据从虚拟串行端口(通过 USB)流式传输到我的应用程序。 MainActivity 有一个处理程序,用于处理来自 USB 服务的消息,类似于提供的示例: https://github.com/felHR85/UsbSerial/blob/master/example/src/main/java/com/felhr/serialportexample/MainActivity.java

我的应用程序有几个活动,如果某些数据通过串行端口,其中许多活动的视图应该会改变。例如,TextView 可能需要更新显示的文本,Button 应启用或禁用。

为了在每个活动中操作onCreate 方法之外的视图,我尝试过的最简单的方法是将视图声明为private static,但我在很多地方都看到这是一种不好的做法。我将视图引用设置回 null,如此处所述(在“2.静态视图”下),我认为,以避免潜在的内存泄漏:https://blog.nimbledroid.com/2016/09/06/stop-memory-leaks.html 我仍然不喜欢 android Studio 中的 Lint 指示“不要将 Android 上下文类放在静态字段中”这一事实。而且这种做法似乎普遍不受欢迎。

每个活动都有一个public static boolean isActive,在onResume 中设置true,在onPause 中设置false

来自MainActivity 的处理程序根据当前正在运行的活动(例如SecondActivity.isActive==true)决定如何处理传入的串行数据。然后它从当前正在运行的活动(例如SecondActivity.updateViews(serialdata))中调用public static 方法,该活动可以访问静态视图引用以执行它需要的操作(例如myTextView.setText(serialdata)

如果我不应该保留对视图的静态引用,有什么替代方法可以实现我所需要的,即从MainActivity 中的处理程序更新SecondActivity 中的视图元素,而SecondActivity 是已经运行了吗?

【问题讨论】:

Activity 可以在您离开后立即被杀死,因此在暂停后运行处理程序是违反生命周期的。转到开发者选项并启用“不保留活动” - 这会模拟内存不足的环境,在这种环境中,所有活动都会在您离开后立即被终止。 【参考方案1】:

MainActivity 有一个处理程序,用于处理来自 USB 服务的消息

这不是一个好计划。

我的应用程序有几个活动,如果某些数据通过串行端口,其中许多活动的视图应该会改变。

这说明了为什么不好的计划不好。来自串行端口的数据并非专门绑定到MainActivity...那么为什么MainActivity 会处理USB 服务消息?

(也很可能您不应该在这里有多个活动,而是有一个包含多个片段的活动,但我暂时将其放在一边)

什么是实现我需要的替代方法

我不知道串行端口的另一端是什么导致消息被发送。出于这个答案的目的,我将其称为“事物”。

步骤#1:创建ThingyRepository。这将是一个管理 USB 串行连接并接收消息的类(带有一个单例实例)。它将根据过去的消息 (ThingyState) 保留当前状态的某种表示,并在新消息进入时更新该状态。

第 2 步:让 ThingyRepository 公开某种“反应式 API”。这可能是现代的东西,例如LiveData 或 RxJava。它可能是更老的东西,比如基于回调的 API。无论哪种方式,您都希望ThingyRepository 在状态更改时将更新的ThingyState 对象传递给相关方(“观察者”)。因此,ThingyRepository 将 USB 串行消息转换为更新的状态,并根据需要发出这些状态。

第 3 步:让您的 UI 观察 ThingyRepository,接收 ThingyState 对象,并根据这些状态更新 UI。理想情况下,您将使用ViewModel 来调解这些通信,以处理Android 的配置更改(屏幕旋转等)。但是,如果您想保持“老派”,该活动可以使用您的ThingyRepository 注册回调,其中ThingyRepository 可以使用新的ThingyState 调用回调,因为数据会根据 USB 消息发生变化。

现在,您已将状态更改与任何单个活动分离。每个活动都可以负责根据新状态确定自己的 UI 中需要更改的内容。而且,您不再需要静态视图。

【讨论】:

其他一些注意事项:我需要支持Android 6.0。该应用程序并非旨在作为通用用途,而是用于仅限于运行该应用程序的特定手机。它不会旋转视图。 @yorisimo:这些都不会改变我的答案。 抱歉,我在完成之前点击了提交的评论。首先,我要感谢 LiveData/ViewModel 的建议。这需要Android 8.0吗?如果是这样,我将遵循“老派”的建议 @yorisimo:“这需要 Android 8.0 吗?” -- 不,它们肯定可以在 Android 6.0 上运行,甚至更早。 我发现关于 ViewModel、LiveData 和 Room 的 Smartherd youtube 教程对理解这些概念很有帮助。

以上是关于避免静态视图引用,但启用不同的活动来修改视图的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 应用程序的视图中引用静态文件

滚动视图顶部的静态按钮 android studio

在情节提要中使用 iOS 静态库公共视图控制器?

从静态布局中删除视图? (空指针)

高级UML14个图

想要创建一个很酷的静态 UI 但:“静态表视图仅有效......”