时间旅行是一个强大的调试工具,它允许你记录所有来自活跃的Stores的事件和状态。当事件被记录后你可以浏览、重演和调试它。它的核心功能是多平台,被所有支持目标实现。然而,一些特定的功能只能在特定的平台上使用。
时间旅行是一种调试工具,它可能会影响性能。理想情况下它不应该在生产环境中使用。
启动并使用时间旅行有三个主要步骤:
Store的工厂提供一个time-travel-aware,这是StoreFactory的变体。TimeTravelStoreFactory用于创建Store的实例,它能够记录和重演事件。在调试构建中,StoreFactory的变体能够通过DI传递给所有Store工厂,而不是DefaultStoreFactory。
本节介绍的功能可用于所有受支持的目标。
假设有以下Store工厂:
internal class CalculatorStoreFactory(private val storeFactory: StoreFactory) {
fun create(): CalculatorStore =
object : CalculatorStore, Store<Intent, State, Nothing> by storeFactory.create(
name = "CounterStore",
// ...
) {
}
// 其他代码
}
它接受一个StoreFactory并用它来创建CalculatorStore的实例。现在可以传递任何StoreFactory。如果你想启用时间旅行,只要传递TimeTravelStoreFactory的实例即可:
val storeFactory = TimeTravelStoreFactory()
CalculatorStoreFactory(storeFactory).create()
也可以组合它和LoggingStoreFactory:
val storeFactory = LoggingStoreFactory(TimeTravelStoreFactory())
CalculatorStoreFactory(storeFactory).create()
通常需要在主程序的某处定义一个全局的StoreFactory,并将它传递给所有依赖项。
每个启用了时间旅行的app都有一个TimeTravelController的全局实例。每个Store自动连接到这个控制器。这个控制器接受来自外部的各种指令、来自以注册的Stores的记录事件、替换状态和重新触发事件用于调试。
为了允许远程控制,app应该运行一个时间旅行服务端。服务端绑定了TimeTravelController和外部世界。服务端的实现在不同的平台是不同的。目前,以下的目标受支持:
android和jvmios,tvos,watchos和macosjs),只支持谷歌浏览器为其他平台实现服务端应该没有技术限制。作者欢迎提issue。
所有的服务端实现(除了JavaScript)是基于TCP的。默认端口是6379,端口可以在初始化期间显式更改。
通信协议是开放的,但被认为是内部的。不同版本之间没有兼容性保证。
首先,在app模块中导入时间旅行依赖项,替换<version>为最后一个发行版本。
implementation("com.arkivanov.mvikotlin:mvikotlin-timetravel:<version>")
在Application类的onCreate()中开始时间旅行。
class App : Application() {
private val timeTravelServer = TimeTravelServer()
override fun onCreate() {
super.onCreate()
timeTravelServer.start()
}
}
由于时间服务服务端确实使用了设备上的互联网与开发机器进行通信,因此即使应用程序不使用互联网,您也需要在AndroidManifest.xml中声明使用互联网权限。
首先,在app模块中导入时间旅行依赖项,替换<version>为最后一个发行版本。
implementation("com.arkivanov.mvikotlin:mvikotlin-timetravel:<version>")
在应用的main函数中创建一个TimeTravelServer的实例并提供runOnMainThread参数,这可以是SwingUtilities.invokeLater {}或其他被使用的coroutines/Reaktive。
fun main() {
TimeTravelServer(runOnMainThread = { SwingUtilities.invokeLater(it) })
.start()
}
为了在Drawin/Apple设备上设置TimeTravelServer,mvikotlin-timetravel依赖项必须在build.gradle.kts的共享模块中导入。与此同时,mvikotlin-timetravel模块必须作为api依赖项添加。这可以在commonMain源集或只在Dawwin源集中完成。
kotlin {
ios {
binaries {
framework {
export("com.arkivanov.mvikotlin:mvikotlin-timetravel:<version>")
}
}
}
sourceSets {
named("commonMain") {
dependencies {
api("com.arkivanov.mvikotlin:mvikotlin-timetravel:<version>")
}
}
}
}
然后在AppDelegate中启动TimeTravelServer的实例。
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
private let s = TimeTravelServer()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 在应用启动后重写定制点。
s.start()
return true
}
}
首先,在app模块中导入时间旅行依赖项,替换<version>为最后一个发行版本。
implementation("com.arkivanov.mvikotlin:mvikotlin-timetravel:<version>")
在应用的main函数中启动TimeTravelServer。
fun main() {
TimeTravelServer().start()
// 重置代码
}
时间旅行客户端与服务端进行通信,并提供UI用于控制功能和显示数据。目前提供了三种客户端变体。
Intellij IDEA插件可以在IDE中直接使用。目前只能连接安卓应用。
可以从Intellij IDEA Marketplace找到该插件,可以在Intellij IDEA和Android Studio中直接安装。在Settings -> Plugins -> Marketplace标签的搜索栏中查找“MVIKotlin”。
该插件使用ADB转发TCP端口6379。
首先确保TimeTravelServer在应用中运行,然后运行安卓应用并打开IDE中的时间旅行插件,可以单击“连接”并开始记录状态更改。插件首次运行时会询问adb路径。
桌面客户端应用程序提供了与IntelliJ IDEA插件类似的功能。但它也可以连接到JVM和Darwin/Apple应用程序。
桌面时间旅行客户端应用程序尚未发布,因此您需要从源代码构建并运行它。可以运行以下命令(至少需要JDK11):
./gradlew :mvikotlin-timetravel-client:app-desktop:run
客户端通过TCP连接服务端。
连接到已经运行了TimeTravelServer的安卓应用的简单方法是打开设置并选择 “Connect via ADB”。然后点击 “Connect” 按钮,客户端将提示您使用 adb 可执行路径,然后应建立连接。客户端使用ADB转发TCP端口。
连接到非安卓应用(或连接到安卓应用但不使用ADB),打开设置并取消选择 “Connect via ADB”,输入设备的主机地址。如果是本地运行的设备,主机地址通常是localhost。对于远程设备,主机地址应该明确指定。请参阅设备的设置以找到它的TCP地址。在任何情况下,设备的端口应该是可连接的(例如拥有权限、端口在白名单中)。
时间旅行客户端是使用Compose for Desktop实现的,因此组装一个发行版是可行的。请参阅 documentation page。
谷歌浏览器扩展提供了与其他时间旅行客户端类似的功能,但专门为Web应用程序设计。
谷歌浏览器扩展程序目前是实验性的。最终它将被提升为稳定或删除。
可以从Chrome Web Store安装插件。
这个插件增加了开发者工具面板,它的外观和工作原理与其他时间旅行客户类似。确保在Web应用程序中已经启动TimeTravelServer。当web页面被加载时,右键并选择 “Inspect” 目录项。导航到“MVIKotlin”工具面板并单击“Connect”按钮。该插件会在web页面中注入特殊脚本,它在TimeTravelServer和插件中代理消息。
每当时间旅行客户端连接到应用时,它可以开始记录事件。按下“Start recording”按钮开始记录。所有记录的事件将会出现在左侧的列表中。按下“Stop recording”停止记录。
当记录结束后,应用会进入检查状态。在这个状态下所有的Stores会从输入和输出断开连接,所有的事件会累积并推迟到检查结束后执行。
每一个记录事件都能被检查。在列表中选择一个事件,细节会出现在右侧。事件细节的精确表示依赖于时间旅行服务器的实现,在不同的平台上有所不同。
安卓和JVM目标的时间旅行服务器使用反射以精确解析对象属性。
Darwin/Apple目标的时间旅行服务器只使用了toString函数。建议定义states,intents,actions和messages为数据类。
JavaScript目标的时间旅行服务器使用JSON.stringify函数。类似于Darwin/Apple,也建议使用数据类。
在检查状态期间,Store的状态可以回滚和重演,会用到下面这些按钮:
UI总是会展示当前选择的状态。
在检查状态时,每个记录事件都可以被再一次触发。一个典型的使用情况是记录app一个不正确的行为,然后在代码中设置断点并触发一个记录事件。要触发一个事件,在列表中选择它,然后单击“Debug the selected event”按钮。
如果触发的事件是一个Intent或一个Action,每个事件的相应Store的Executor的新调试实例会被创建。Executor相应的调试实例用相同的State,与记录时的State相同。在调试会话期间调度的所有Messages都通过 Reducer传递,并且Executor的调试实例的State会相应更新。任何在事件调试会话期间被发布的Label会被忽略。
如果触发的事件是一个Message,Reducer只会带着Message和对应的State被调用,它的结果会被忽略。
这个功能目前只支持JVM和安卓应用。这个功能只有在所有相关类(Intents, Actions, Messages, States, 和Labels)必须实现Serializable接口。MVIKotlin模块提供了方便的 JvmSerializable接口,它可以在common源集中使用。
如果要导出记录事件,按下“Export events”按钮。选择一个文件夹并键入文件名。所有的事件会被序列化并保存在文件中。
如果要导入之间导出的事件,按下“Import events”按钮并选择一个文件。所有的事件会从文件被反序列化并应用于当前Stores。
在导入文件时应用程序的代码应该和导出时相同。反序列化的类要符合序列化时的类。否则它的行为是不确定的。
如果要结束检查,按下“Cancel”按钮,之后在检查期间等待队列中的Intents和Labels都会自动处理。
我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查
这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build
我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总
深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal
我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时
我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or
因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实
在Ruby中,以毫秒为单位获取自纪元(1970)以来的当前系统时间的正确方法是什么?我试过了Time.now.to_i,好像不是我想要的结果。我需要结果显示毫秒并且使用long类型,而不是float或double。 最佳答案 (Time.now.to_f*1000).to_iTime.now.to_f显示包含十进制数字的时间。要获得毫秒数,只需将时间乘以1000。 关于ruby-以毫秒为单位获取当前系统时间,我们在StackOverflow上找到一个类似的问题: