没有 AI 之前,我习惯找一条关键流程去看代码,边看边画类图和时序图,一来加深理解,二来避免很快就遗忘。但我不敢说这个过程就真的很轻松。我在想,如果有人提前就帮我准确地画出我想要类图和时序图,我是不是就能更轻松地读代码了?当然,这些图最好还能轻松地调整。第一个原因是代码会更新,所以图也必须能同步更新;第二个原因是关注点会变,比如一开始我们并不关注异常处理和次要分支,所以可以忽略它们,但随着对代码理解的加深,这些细节可能会变得不容忽视。
privatefunonDecksLoaded( result: DeckNode, collectionHasNoCards: Boolean, ) { Timber.i("Updating deck list UI") hideProgressBar() // Make sure the fragment is visible if (fragmented) { invalidateOptionsMenu() studyoptionsFrame!!.visibility = if (collectionHasNoCards) View.GONE else View.VISIBLE } dueTree = result }
我的第一个问题是:
generate a sequence diagram to show me how the data dueTree is fetched and displayed
sequenceDiagram participant DP as DeckPicker participant CM as CollectionManager participant S as Scheduler participant D as Decks participant DA as DeckAdapter participant UI as UserInterface
Note over DP, UI: User interacts with DeckPicker DP->>CM: isOpenUnsafe() alt Collection is open CM-->>DP: true DP->>DP: performBackupInBackground() DP->>DP: launchCatchingTask { ... } DP->>S: sched.deckDueTree() activate S S->>D: Access deck data activate D D-->>S: Deck data deactivate D S-->>DP: DeckNode (dueTree) deactivate S DP->>DP: onDecksLoaded(dueTree, collectionHasNoCards) DP->>UI: hideProgressBar() alt fragmented DP->>UI: invalidateOptionsMenu() UI->>UI: studyoptionsFrame!!.visibility = if (collectionHasNoCards) View.GONE else View.VISIBLE end DP->>DP: dueTree = result DP->>DP: launchCatchingTask { renderPage(collectionHasNoCards) } DP->>DP: renderPage(collectionHasNoCards) alt tree is null DP->>DP: updateDeckList() DP->>DP: launchCatchingTask { ... } DP->>S: sched.deckDueTree() activate S S->>D: Access deck data activate D D-->>S: Deck data deactivate D S-->>DP: DeckNode (dueTree) deactivate S DP->>DP: onDecksLoaded(dueTree, collectionHasNoCards) DP->>UI: hideProgressBar() alt fragmented DP->>UI: invalidateOptionsMenu() UI->>UI: studyoptionsFrame!!.visibility = if (collectionHasNoCards) View.GONE else View.VISIBLE end DP->>DP: dueTree = result DP->>DP: launchCatchingTask { renderPage(collectionHasNoCards) } DP->>DP: renderPage(collectionHasNoCards) end alt isEmpty DP->>UI: deckPickerContent.visibility = View.GONE UI->>UI: noDecksPlaceholder.visibility = View.VISIBLE DP->>UI: supportActionBar?.subtitle = null DP->>DA: submit(emptyList(), false, -1) DA->>UI: Update UI with empty list else not isEmpty DP->>UI: deckPickerContent.visibility = View.VISIBLE UI->>UI: noDecksPlaceholder.visibility = View.GONE DP->>DA: submit(tree.filterAndFlatten(currentFilter), tree.children.any { it.children.any() }, withCol { decks.current().getLong("id") }) DA->>UI: Update UI with filtered and flattened data DP->>UI: supportActionBar?.subtitle = ... DP->>DP: scrollDecklistToDeck(current) DP->>DP: viewModel.focusedDeck = current end DP->>DP: launchCatchingTask { ... } DP->>S: sched.studiedToday() activate S S-->>DP: studiedToday() deactivate S DP->>UI: reviewSummaryTextView.text = ... UI->>UI: Update review summary else Collection is not open CM-->>DP: false end
我暂时只聚集核心流程,不关注异常处理和空数据处理。所以我的第二个问题是:
Remove some unnecessary details like false condition and exception handling from the diagram to make it more clear
sequenceDiagram participant DP as DeckPicker participant CM as CollectionManager participant S as Scheduler participant D as Decks participant DA as DeckAdapter participant UI as UserInterface
Note over DP, UI: User interacts with DeckPicker DP->>CM: isOpenUnsafe() alt Collection is open CM-->>DP: true DP->>DP: performBackupInBackground() DP->>DP: launchCatchingTask { ... } DP->>S: sched.deckDueTree() activate S S->>D: Access deck data activate D D-->>S: Deck data deactivate D S-->>DP: DeckNode (dueTree) deactivate S DP->>DP: onDecksLoaded(dueTree, collectionHasNoCards) DP->>UI: hideProgressBar() alt fragmented DP->>UI: invalidateOptionsMenu() UI->>UI: studyoptionsFrame!!.visibility = if (collectionHasNoCards) View.GONE else View.VISIBLE end DP->>DP: dueTree = result DP->>DP: launchCatchingTask { renderPage(collectionHasNoCards) } DP->>DP: renderPage(collectionHasNoCards) alt tree is null DP->>DP: updateDeckList() Note over DP: Recursive call to fetch dueTree else not null alt isEmpty DP->>UI: deckPickerContent.visibility = View.GONE UI->>UI: noDecksPlaceholder.visibility = View.VISIBLE DP->>DA: submit(emptyList(), false, -1) DA->>UI: Update UI with empty list else not isEmpty DP->>UI: deckPickerContent.visibility = View.VISIBLE UI->>UI: noDecksPlaceholder.visibility = View.GONE DP->>DA: submit(tree.filterAndFlatten(currentFilter), tree.children.any { it.children.any() }, withCol { decks.current().getLong("id") }) DA->>UI: Update UI with filtered and flattened data DP->>UI: supportActionBar?.subtitle = ... DP->>DP: scrollDecklistToDeck(current) DP->>DP: viewModel.focusedDeck = current end end DP->>DP: launchCatchingTask { ... } DP->>S: sched.studiedToday() activate S S-->>DP: studiedToday() deactivate S DP->>UI: reviewSummaryTextView.text = ... UI->>UI: Update review summary end
这个图仍然有些琐碎。我继续让 Gemini 去掉不必要的细节,第三个问题是:
It’s not fragmented and the tree always has data. Continue to remove these unnecessary details from the diagram.
sequenceDiagram participant DP as DeckPicker participant CM as CollectionManager participant S as Scheduler participant D as Decks participant DA as DeckAdapter participant UI as UserInterface
Note over DP, UI: User interacts with DeckPicker DP->>CM: isOpenUnsafe() alt Collection is open CM-->>DP: true DP->>DP: performBackupInBackground() DP->>DP: launchCatchingTask { ... } DP->>S: sched.deckDueTree() activate S S->>D: Access deck data activate D D-->>S: Deck data deactivate D S-->>DP: DeckNode (dueTree) deactivate S DP->>DP: onDecksLoaded(dueTree, collectionHasNoCards) DP->>UI: hideProgressBar() DP->>DP: dueTree = result DP->>DP: launchCatchingTask { renderPage(collectionHasNoCards) } DP->>DP: renderPage(collectionHasNoCards) DP->>UI: deckPickerContent.visibility = View.VISIBLE UI->>UI: noDecksPlaceholder.visibility = View.GONE DP->>DA: submit(tree.filterAndFlatten(currentFilter), tree.children.any { it.children.any() }, withCol { decks.current().getLong("id") }) DA->>UI: Update UI with filtered and flattened data DP->>UI: supportActionBar?.subtitle = ... DP->>DP: scrollDecklistToDeck(current) DP->>DP: viewModel.focusedDeck = current DP->>DP: launchCatchingTask { ... } DP->>S: sched.studiedToday() activate S S-->>DP: studiedToday() deactivate S DP->>UI: reviewSummaryTextView.text = ... UI->>UI: Update review summary end
fungenerateWaveformFloats( count: Int, min: Float = 42f, max: Float = 2100f, baseFrequency: Float = 0.1f, // Adjust for overall wave speed amplitudeVariation: Float = 0.5f, // Adjust for how much the amplitude changes frequencyVariation: Float = 0.2f // Adjust for how much the frequency changes ): List<Float> { require(min < max) { "Min value must be less than max value" } require(count > 0) { "Count must be greater than 0" }
val waveform = mutableListOf<Float>() val random = Random(System.currentTimeMillis()) // Seed for more varied results
var currentAmplitude = (max - min) / 2f// Start in the middle var currentFrequency = baseFrequency
for (i in0 until count) { // Introduce some randomness to amplitude and frequency currentAmplitude += (random.nextFloat() - 0.5f) * (max - min) * amplitudeVariation currentFrequency += (random.nextFloat() - 0.5f) * baseFrequency * frequencyVariation
// Clamp amplitude to stay within bounds currentAmplitude = currentAmplitude.coerceIn(min, max)
// Generate a sine wave value val sineValue = sin(i * currentFrequency)
// Scale and shift the sine wave to fit the desired range val scaledValue = (sineValue + 1) / 2 * (currentAmplitude - min) + min