Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How Android Uses Data Structures Behind The Scenes

Avatar for HyunWoo Lee HyunWoo Lee
September 11, 2025

How Android Uses Data Structures Behind The Scenes

This is the speaker deck for How Android Uses Data Structures Behind The Scenes, presented at DroidKaigi2025 (Tokyo, Japan).

DroidKaigi2025 (Tokyo, Japan)에서 진행한 How Android Uses Data Structures Behind The Scenes의 Speaker Deck입니다.

Avatar for HyunWoo Lee

HyunWoo Lee

September 11, 2025
Tweet

More Decks by HyunWoo Lee

Other Decks in Programming

Transcript

  1. HyunWoo Lee DroidKaigi 2025 Android/React Native Engineer, Viva Republica(Toss) Organizer,

    GDG Korea Android/Kotlin User Groups Seoul How Android Uses Data Structures : Behind The Scenes
  2. Data Structures/Algorithm - Are these useful? Part 1 Data Structures

    In Practice Part 2 Data Structures In Android Framework/Libraries Part 3 Summary Part 4 Agenda DroidKaigi 2025
  3. Y es, Of Course!! CAUTION It doesn’t mean the “rote

    memorization” of data structure knowledges
 Time Complexties for CRUD operations Pseudo code implementations DroidKaigi 2025
  4. Y es, Of Course!! DroidKaigi 2025 The key points are

    “decision- making” and “designing the appropriate data structure” Which data structure should be used in a given situation? Designing a new data structure to solve your problems.
  5. Simple Example : Instagram Feed DroidKaigi 2025 Goal Store IDs

    of posts that a user has liked. How would you implement this feature in code?
  6. DroidKaigi 2025 1 2 // typealias Id = Int val

    ids mutableListOf Id () = < >
  7. DroidKaigi 2025 1 2 // typealias Id = Int val

    ids mutableSetOf Id () = < >
  8. List vs Set DroidKaigi 2025 In this case, “Set” is

    more appropriate way. Preventing duplicate elements (unless a multiset) In Kotlin/JVM Set checks are O(1) on average, while List needs O(n) checks for duplicates List → ArrayList Set → LinkedHashSet
  9. Development in AI Era: How to Deal with it? DroidKaigi

    2025 Modern AI Agents’ abilities/ productivity is improving so rapidly In my case, I rely on agents for nearly 80% of feature implementation.
  10. Development in AI Era: How to Deal with it? DroidKaigi

    2025 About 20% of AI-generated code still needs manual correction Due to inefficiency or framework misunderstandings. To solve these issues, we must understand the generated code, identify problems, and fix them ourselves. Strong data structure knowledge and experience with data modeling are essential for resolving such challenges.
  11. Data Structures = “Design” of Data DroidKaigi 2025 Example: LRU

    Cache Almost of developers know it’s features Reorder elements by access history Evict LRU entry Q) What is the core in LRUCache?
  12. DroidKaigi 2025 Optimize access single elements Easy to re-order Maybe

    use HashMap-like thing? Single element(cache-hit node) should move to last. 
 → So doubly-linked list is more useful.
  13. DroidKaigi 2025 1 2 3 4 5 6 7 //

    LruCache.java // .... package public class private final android.util; LruCache K, V { LinkedHashMap K, V map; } < > < >
  14. LinkedHashMap DroidKaigi 2025 LinkedHashMap use both HashMap and Doubly-LinkedLists HashMap

    Get/find an element using fast lookup Doubly-LinkedLists Connects each entry To update the position of nodes efficiently
  15. Dagger(Hilt): Graceful DI Library DroidKaigi 2025 Dagger analyzes module dependencies

    at build time, checking whether there are any circular references or invalid relationships among the modules. How does Dagger work under the hood?
  16. DroidKaigi 2025 1 2 3 class constructor private val DroidKaigi

    ( hello EveryOne ) @Inject : DroidKaigi EveryOne
  17. DroidKaigi 2025 1 2 3 class constructor private val DroidKaigi

    ( hello EveryOne ) @Inject : DroidKaigi EveryOne Node(Edge) Node(Edge) Link
  18. DAG’s Main Features DroidKaigi 2025 2 Main Features Directed Graph

    All edges are directed in the same way. Acyclic Graph There are no closed loops (cycles) among the edges.
  19. How Dagger(Hilt) Detects Circular Dependency at Compile Time? DroidKaigi 2025

    Dagger uses the principle that: “If there is a path from node u to node v, there is no path from v back to u.”
  20. Dagger: How to make a dependency graph? ComponentProcessingStep BindingGraphFactory Validators

    BindingGraph + Resolver Collect components & modules → ComponentDescriptor Discover bindings (like @Inject) Resolve graph with BindingGraphFactory + Resolver Validate graph Missing/duplicate/conflicting bindings Scope & visibility rules DroidKaigi 2025
  21. How Dagger(Hilt) Detects Circular Dependency at Compile Time? DroidKaigi 2025

    There are classical algorithms to find cycle detection in DAG Tarjan’s SCC(Strongly connected component) Topological Sorting But, these methods can’t show an exact cycle path (using in error message). → Dagger choose BFS to detect shortest path between two nodes.
  22. Before Detection - Cycle Breaking Edges Dagger treats these edges

    as cycle-breaking: Provider<T>, Lazy<T> Map<K, Provider<V>> (value-side provider) Why? Cycles that include providers/lazy are allowed and broken by indirection at runtime codegen. “If a well-formed graph has a cycle, it necessarily contains a Provider/Lazy; Dagger breaks it by inserting a dummy Provider and wiring around the loop.” DroidKaigi 2025
  23. DroidKaigi 2025 1 2 3 4 5 6 7 8

    9 10 Set EndpointPair Node dependencyEndpointPairs dependencyGraph. (). (); Set EndpointPair Node visited (dependencyEndpointPairs. ()); (EndpointPair Node endpointPair dependencyEndpointPairs) { (endpointPair, dependencyGraph, visited) . (cycle (cycle, bindingGraph, diagnosticReporter) ); } < < >> = < < >> = < > : -> asGraph edges newHashSetWithExpectedSize size cycleContainingEndpointPair ifPresent reportCycle for DependencyCycleValidator
  24. DroidKaigi 2025 1 2 3 4 5 6 7 8

    Optional Cycle Node ( EndpointPair Node endpoints, ImmutableNetwork Node, DependencyEdge dependencyGraph, Set EndpointPair Node visited) { ( visited. (endpoints)) { Optional. (); } private if return < < >> < > < > < < >> ! cycleContainingEndpointPair add empty // don't recheck endpoints we already know are part of a cycle DependencyCycleValidator
  25. DroidKaigi 2025 1 2 3 4 5 6 7 8

    9 10 11 Optional Cycle Node ( EndpointPair Node endpoints, ImmutableNetwork Node, DependencyEdge dependencyGraph, Set EndpointPair Node visited) { ImmutableList Node cycleNodes (dependencyGraph, endpoints. (), endpoints. ()); (cycleNodes. ()) { Optional. (); } private if return < < >> < > < > < < >> < > = cycleContainingEndpointPair shortestPath target source isEmpty empty // ... // If there's a path from the target back to the source, there's a cycle. DependencyCycleValidator
  26. DroidKaigi 2025 1 2 3 4 5 6 class constructor

    private val class constructor private val class constructor private val class constructor private val class constructor private val class constructor val HomeViewModel ( useCase GetFeed) GetFeed ( repo FeedRepository) FeedRepository ( api ApiService) ApiService ( auth AuthInterceptor) AuthInterceptor ( session SessionManager) SessionManager ( vm HomeViewModel) @Inject : @Inject : @Inject : @Inject : @Inject : @Inject : BFS - In Real World Practice
  27. Is ViewModel → UseCase part of a cycle? Step Action

    Next Predecessor Change Hit ViewModel? 0 Seed: enqueue UseCase successor [Repo] pred[Repo] = UseCase X 1 Pop Repo → successors {Api} [Api] pred[Api] = Repo X 2 Pop Api → successors {Auth} [Auth] pred[Auth] = Api X 3 Pop Auth → successors {Session} [Session] pred[Session] = Auth X 4 Pop Session → successors {VM} - pred[VM] = Session O DroidKaigi 2025
  28. DroidKaigi 2025 What Dagger Reports: Error Log 1 2 3

    4 5 6 7 8 error Found a dependency cycle HomeViewModel → GetFeedUseCase → FeedRepository → ApiService → AuthInterceptor → SessionManager → HomeViewModel : :
  29. How do we fix it? DroidKaigi 2025 Use Provide<T>, Lazy<T>

    Check for scope consistency. Move the back-reference into events or flows to avoid constructor-time loops.
  30. UI System: XML vs Compose DroidKaigi 2025 View(XML) System View

    Tree Jetpack Compose Slot Table LayoutNode Tree
  31. How do we update the State? In View System DroidKaigi

    2025 Each View Node in a View Tree maintains its own state UI updates require direct access → modify the node’s state values
  32. Why “ViewBinding” Is the Preferred Way? DroidKaigi 2025 findViewById DFS

    traversal on each access ViewBinding caches views at init → no repeated lookups
  33. DroidKaigi 2025 1 2 3 4 5 6 7 8

    9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 T extends View T ( int id) { (id mID) { (T) ; } View[] mChildren; int len mChildrenCount; (int i ; i len; i ) { View v [i]; ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) ) { v v. (id); (v ) { (T) v; } } } ; } @Override < > @IdRes == = = = < ++ = == = != protected if return this final where final for where if if null return return null findViewTraversal findViewById 0 0 ViewGroup Iterates over all children in ViewGroup For each child → calls findViewById again If child is a ViewGroup → process repeats from its first child → DFS Traversal
  34. How do we update the State? In Jetpack Compose DroidKaigi

    2025 State Tree Part of Compose Runtime State update → triggers recomposition of relevant UI Layout Tree Part of Compose UI Responsible for rendering the UI
  35. Why Did Compose Seperate State From UI? DroidKaigi 2025 Lightweight

    representation of UI State Tree ≈ Virtual DOM (React) No heavy View object tree → better performance State Tree ≠ strict tree → can take other forms for further optimization
  36. SlotTable And Gap Buffer : State Tree DroidKaigi 2025 State

    Tree Store UI relevant informations of UI Node Identity, metadata, state etc. To update only the necessary parts of the tree SlotTable Actual implementation of State Tree
  37. SlotTable And Gap Buffer : State Tree DroidKaigi 2025 Gap

    Buffer Array-based data structure with pre-allocated extra space (gap) Enables efficient insert/delete in the middle (gap) No need to shift all elements each time Operations use the pre- allocated gap
  38. DroidKaigi 2025 1 2 3 4 5 6 7 8

    9 10 @Composable = @Composable = @Composable = @Composable = @Composable : = = @Composable = @Composable : @Composable -> = = () ( ) () ( ) () ( ) () ( ) (value Int ) ( $value ) () ( ) (row RowScope.() Unit) { (Modifier. (). (vertical .dp), content row) } private fun private fun private fun private fun private fun private fun private fun A Text B Text C Text D Text E Text X Text Buttons Row fillMaxWidth padding "A" "B" "C" "D" "E(value= )" "X" 0 8 Composable Groups Example
  39. DroidKaigi 2025 1 2 3 4 5 6 7 8

    9 10 11 12 13 @Composable = = ! fun var by if () { visible remember { ( ) } (Modifier. ( .dp)) { ( ) (); (); () (visible) { () } (); () Buttons { (onClick { visible visible }) { ( ) } } } } InsertionDemo mutableStateOf Column padding Text A B C X D E Button Text false 12 "Insertion (X at the gap)" "Toggle X" Add a new Composable in the gap
  40. DroidKaigi 2025 1 2 3 4 5 6 7 8

    9 10 11 12 13 @Composable = = ! fun var by if () { showC remember { ( ) } (Modifier. ( .dp)) { ( ) (); () (showC) { () } (); () Buttons { (onClick { showC showC }) { ( ) } } } } BackspaceDemo mutableStateOf Column padding Text A B C D E Button Text true 12 "Backspace (remove left of gap = C)" "Toggle C" Delete a Composable
  41. Summary DroidKaigi 2025 Data structures form the foundation for how

    we think about building programs. Key Point Not about memorizing data structures About developing the judgment to choose the right one for the problem No direct chance to apply? → Analyze existing code Gain indirect design & decision-making experience