Android UI Design: Limitations of Views

Opeyemi Olorunleke
3 min readAug 26, 2023

--

source: Pexels

A User Interface (UI) is the point of interaction between a user and a system. It encompasses the visual elements used to reflect and/or control the state of the system. This “state” refers to the condition of the system at a specific moment.

Since the inception of Android development, Android Views have served as the standard approach for creating native Android UI. However, they have now been superseded by Jetpack Compose. To fully grasp the ingenuity of Compose, it’s crucial to analyze the limitations posed by traditional views:

  1. Lack of Declarative Syntax
  2. Complex UI State Management
  3. XML Overhead
  4. Performance Concerns
  5. Testing Challenges

1. Lack of Fully Declarative Syntax

Imperative UI design and declarative UI design are two different approaches to creating user interfaces in software applications. They differ in how they specify and manage the UI components. Learn more about Imperative and declarative programming.

Traditional views are partially imperative and declarative.

The UI is initially formed through XML, utilizing a declarative approach (transformed into views via setContentView()). Subsequently, Kotlin/Java is employed for state management and dynamic UI element addition, following an imperative methodology, this is where the problem is.

Dynamic UI element addition.

This can be tricky depending on the type of layout that was initially selected in XML. If you used relative or constraint layout you would have to initially find how each element are constrained/related, adjust the constraints/relativity of the surrounding views before positioning the UI element. This is error prone and time consuming.

State management

Managing the state of UI is challenging using views for the following reasons:

  1. Mutability Complexity: In imperative programming, variables can change state at any point in the program’s execution. Managing state changes manually can lead to complex and hard-to-predict behaviors. As the program grows, it becomes increasingly difficult to track all the places where state is modified, leading to bugs and unintended side effects.
  2. Global State: Imperative programs often rely on global variables or state that can be accessed and modified from anywhere in the program. This can make it difficult to isolate and control how different parts of the program interact with the same state, leading to issues like race conditions and concurrency problems.
  3. Readability and Maintenance: As state changes become more scattered throughout the codebase, understanding how different parts of the program interact and affect each other becomes challenging. This can result in code that is hard to read, maintain, and debug.
  4. Temporal Coupling: Imperative programs can have tightly coupled dependencies between different parts of the code that manipulate the same state. Changes in one part of the code can unexpectedly affect other parts, making it harder to reason about the program’s behavior.
  5. Undo/Redo : Implementing features like undo/redo functionality can be complex in an imperative setting due to the lack of clear snapshots of program state at different points in time.
  6. Testing Difficulty: Writing comprehensive tests for imperative code that involves state changes can be challenging. Tests need to account for all possible state transitions and interactions, leading to a large number of test cases.

2. Complex UI State Management

With Views, UI states have to be manually updated via setter functions. This is a common source of bugs especially in complex applications because it is difficult to anticipate all possible states of the system due to nature of app and dynamic system configuration changes (locale change, foldable screen, window resizing etc) .

Libraries like RxJava was used to manage that complexity but has it limitation and adds extra layer of complexity.

3. XML Overhead

Traditional Android UI development relies heavily on XML layouts. XML can be verbose and harder to maintain, especially for complex UIs. Constant switching between XML and code for UI updates can be cumbersome.

4. Performance Concerns

Traditional views can suffer from performance issues, especially when dealing with intricate UI elements or dynamic changes. Inefficient layout hierarchies and view recycling complexities can lead to UI jank or slow rendering.

5. Testing Challenges

Unit testing UI components built with traditional views can be challenging due to their tightly coupled nature and reliance on the Android framework.

Conclusion

The imperative approach to implementing Android views is unsuitable for scalable UI design and state management due to need for flexibility. This is where Compose excels.

--

--

Opeyemi Olorunleke

Passionate about solving problems and building scalable apps. I write about AI/ML, software development and personal growth. FOLLOW to not miss new post