Skip to content

RUM-9508: LogsHeavyTraffic scenario for android benchmarks#2629

Merged
aleksandr-gringauz merged 2 commits into
developfrom
aleksandr-gringauz/RUM-9508/logs-scenarios-heavy-4
May 6, 2025
Merged

RUM-9508: LogsHeavyTraffic scenario for android benchmarks#2629
aleksandr-gringauz merged 2 commits into
developfrom
aleksandr-gringauz/RUM-9508/logs-scenarios-heavy-4

Conversation

@aleksandr-gringauz

@aleksandr-gringauz aleksandr-gringauz commented May 5, 2025

Copy link
Copy Markdown
Contributor

What does this PR do?

  1. Implemented LogsHeavyTraffic scenario for Android Benchmarking app that is described here. demo: link

  2. created a synthetics test described here. Link. I checked that is works for my local build.

Motivation

What inspired you to submit this pull request?

Additional Notes

Anything else we should know when reviewing?

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

val component: BenchmarkActivityComponent
) : ViewModel()

internal class MainActivityViewModelFactory(

@aleksandr-gringauz aleksandr-gringauz May 5, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to support screen rotation case. Activity gets recreated, I wanted to make the component stay alive. So I put it into a viewModel. It almost worked.

The only problem for now is that if this is called, then you can't call start again, because executorService is already stopped. If you call start, the app crashes.

I'm not going to fix this now, it isn't critical.

import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory

internal fun <C : Any> Fragment.componentHolderViewModel(factory: ViewModel.() -> C): Lazy<C> {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This thing is used to make dagger component that is used inside a fragment survive configuration change. See this.

@aleksandr-gringauz
aleksandr-gringauz marked this pull request as ready for review May 5, 2025 14:48
@aleksandr-gringauz
aleksandr-gringauz requested review from a team as code owners May 5, 2025 14:48
@codecov-commenter

codecov-commenter commented May 5, 2025

Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 70.00%. Comparing base (dd4ee16) to head (8162d64).

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #2629      +/-   ##
===========================================
- Coverage    70.05%   70.00%   -0.05%     
===========================================
  Files          820      820              
  Lines        30568    30568              
  Branches      5132     5132              
===========================================
- Hits         21413    21397      -16     
- Misses        7726     7727       +1     
- Partials      1429     1444      +15     

see 35 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@aleksandr-gringauz
aleksandr-gringauz force-pushed the aleksandr-gringauz/RUM-9508/logs-scenarios-heavy-4 branch from 2ac6506 to d4759cf Compare May 5, 2025 19:18
@aleksandr-gringauz
aleksandr-gringauz force-pushed the aleksandr-gringauz/RUM-9508/logs-scenarios-heavy-4 branch from d4759cf to 2fd7156 Compare May 5, 2025 19:21
Log.DEBUG
)

internal fun Int.stringRepresentation(): String {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make function name more specific, given that receiver type is very generic.

Suggested change
internal fun Int.stringRepresentation(): String {
internal fun Int.logStringRepresentation(): String {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

internal lateinit var viewModel: LogsHeavyTrafficViewModel

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
(parentFragment?.parentFragment as LogsHeavyTrafficHostFragment).component.inject(this)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we are doing it here for the LogsHeavyTrafficHostFragment if in the LogsHeavyTrafficHostFragment.onCreateView we are already doing component.inject(this) call?

@aleksandr-gringauz aleksandr-gringauz May 6, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now it works the following way.

We have a root fragment LogsHeavyTrafficHostFragment that has its own navigation stack and hosts LogsHeavyTrafficFragment and LogsHeavyTrafficSettingsFragment.

LogsHeavyTrafficHostFragment contains a dagger component LogsHeavyTrafficComponent that is used to share state between LogsHeavyTrafficFragment and LogsHeavyTrafficSettingsFragment and provide everything these fragments need, currently it is LogsHeavyTrafficViewModel - shared view model with shared state.

I chose field injection as a way to inject this LogsHeavyTrafficViewModelinto LogsHeavyTrafficFragment, LogsHeavyTrafficSettingsFragment .

The alternative is to create properties in LogsHeavyTrafficComponent:

interface LogsHeavyTrafficComponent {
     val viewModel: LogsHeavyTrafficViewModel
     val navigationManager: LogsHeavyTrafficNavigationManager
}

and in LogsHeavyTrafficFragment and LogsHeavyTrafficSettingsFragment do (parentFragment?.parentFragment as LogsHeavyTrafficHostFragment).component.viewModel.

and in LogsHeavyTrafficHostFragment do component.navigationManager.

These are 2 ways to do the same thing.

why we are doing it here for the LogsHeavyTrafficHostFragment if in the LogsHeavyTrafficHostFragment.onCreateView we are already doing component.inject(this) call?

I am not sure I understand the question. inject(...) just does field injection into the fields annotated by @Inject, it doesn't create a new component, it just uses the component to provide necessary objects.

internal lateinit var viewModel: LogsHeavyTrafficViewModel

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
(parentFragment?.parentFragment as LogsHeavyTrafficHostFragment).component.inject(this)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same question as before

@aleksandr-gringauz
aleksandr-gringauz merged commit a39c5da into develop May 6, 2025
@aleksandr-gringauz
aleksandr-gringauz deleted the aleksandr-gringauz/RUM-9508/logs-scenarios-heavy-4 branch May 6, 2025 08:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants