Advanced Android UI


Advanced Android UI Interview with follow-up questions

1. Can you explain the concept of animations in Android?

Android provides multiple animation systems, and the right choice depends on whether you are using Jetpack Compose or the View system, and what you are trying to animate.

Animations in Jetpack Compose

Compose has a declarative animation API built around state changes. When state changes, Compose can smoothly interpolate between the old and new UI.

  • animateFloatAsState / animateColorAsState / animateDpAsState: animate a single value when it changes. Simple and idiomatic. kotlin val alpha by animateFloatAsState(targetValue = if (visible) 1f else 0f) Box(modifier = Modifier.alpha(alpha)) { ... }
  • AnimatedVisibility: animate the appearance/disappearance of content with enter/exit transitions (fade, slide, scale, expand, shrink).
  • AnimatedContent: animate transitions between different content based on state.
  • updateTransition: coordinate multiple animations between states.
  • rememberInfiniteTransition: create repeating animations (loading spinners, pulsing effects).
  • animate*AsState with spring / tween / keyframes: control the animation spec — spring physics, linear/eased timing, or explicit keyframes.

Compose animations are coroutine-based under the hood and are automatically cancelled and restarted when state changes, avoiding the callback hell of the old API.

Animations in the View system

Property Animator (preferred for Views)

Animates actual properties of a View object. Backed by ValueAnimator and ObjectAnimator. Because it modifies real properties, views respond correctly to touch after animation.

ObjectAnimator.ofFloat(view, "translationX", 0f, 100f).apply {
    duration = 300
    interpolator = DecelerateInterpolator()
    start()
}

AnimatorSet coordinates multiple animators (sequentially or in parallel).

View Animation (legacy, avoid for new code)

The original Animation class (AlphaAnimation, TranslateAnimation, ScaleAnimation, RotateAnimation) and AnimationUtils.loadAnimation(). These animate the visual representation of a view without changing its actual position/state — a click target stays at the original position even though the view appears to have moved. Largely replaced by Property Animator.

Transition Framework

TransitionManager.beginDelayedTransition() and the Transition API (including AutoTransition, Fade, ChangeBounds) animate layout changes automatically. The Navigation Component and Activity transitions use ActivityOptions and SharedElementTransition for inter-screen animations. Compose's Navigation library achieves the same with AnimatedNavHost.

Lottie

For complex, designer-authored animations (from Adobe After Effects), the Lottie library (com.airbnb.android:lottie) or Lottie-Compose is the standard industry approach. Animations are defined in a JSON format and rendered at runtime.

Common interview follow-up: "What is the difference between View Animation and Property Animation?" View Animation moves the drawn representation of a view but not the view itself — touch events still fire at the original location. Property Animation changes the actual property on the view object, so touch events follow the animated position.

↑ Back to top

Follow-up 1

How would you implement a fade-in animation for a button?

To implement a fade-in animation for a button, you can use a View animation in Android. Here's an example of how you can do it programmatically:

Button button = findViewById(R.id.button);
Animation fadeInAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_in);
button.startAnimation(fadeInAnimation);

And here's an example of how you can do it using XML:




Follow-up 2

What is the difference between View animations and Property animations?

The main difference between View animations and Property animations in Android is the level at which they operate. View animations operate on the entire view hierarchy, while Property animations can animate specific properties of an object.

View animations are defined using XML files or programmatically using the Animation class. They can animate the position, size, rotation, and transparency of views. However, they cannot animate specific properties of an object.

Property animations, on the other hand, are defined using the ObjectAnimator class. They can animate properties like translation, rotation, scale, and alpha. Property animations are more flexible and powerful than View animations because they can animate any property of an object, not just the properties of views.

Follow-up 3

How can you use interpolators in animations?

Interpolators in Android animations are used to define the rate of change of an animation over time. They control the acceleration and deceleration of an animation, allowing you to create different effects.

Android provides several built-in interpolators, such as AccelerateInterpolator, DecelerateInterpolator, and LinearInterpolator. You can also create custom interpolators by implementing the Interpolator interface.

To use an interpolator in an animation, you can set it using the setInterpolator() method. Here's an example:

Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_in);
animation.setInterpolator(new AccelerateInterpolator());
view.startAnimation(animation);

Follow-up 4

What are the performance considerations when using animations?

When using animations in Android, there are several performance considerations to keep in mind:

  1. Avoid using heavy animations: Complex animations with a large number of views or high frame rates can consume a lot of CPU and memory resources. This can lead to a decrease in performance and responsiveness of your app.

  2. Use hardware acceleration: Enable hardware acceleration for your animations to offload the rendering process to the GPU. This can improve the performance and smoothness of your animations.

  3. Optimize your animations: Minimize the number of unnecessary animations and optimize the duration and timing of your animations. Use techniques like caching, preloading, and reusing animations to reduce the overhead.

  4. Test on different devices: Test your animations on different devices with varying hardware capabilities to ensure that they perform well on all devices.

By following these considerations, you can create smooth and performant animations in your Android app.

2. What is a nine-patch image and where is it used in Android?

A nine-patch image is a specially formatted PNG file with the extension .9.png that can be stretched to any size while keeping its corners and borders crisp. The "nine-patch" name comes from the fact that the image is divided into a 3×3 grid of nine sections: four corner patches that are never scaled, four edge patches that scale in only one axis, and one center patch that scales in both axes.

How it works

A nine-patch file has a 1-pixel transparent border added around the original image. Black pixels along this border encode the stretching rules:

  • Left border: marks which rows of pixels are allowed to stretch vertically.
  • Top border: marks which columns of pixels are allowed to stretch horizontally.
  • Right border: marks the vertical padding zone (where content is placed inside the image).
  • Bottom border: marks the horizontal padding zone.

Android reads these pixel hints at draw time and scales only the stretchable regions, preserving the appearance of rounded corners, shadows, and borders.

Where it is used

Nine-patches are used for backgrounds that must scale to different sizes while preserving visual details: buttons with rounded corners and shadows, chat bubbles, dialog backgrounds, input field decorations, and notification icons. They have been part of Android since API 1.

How to create one

Android Studio includes the nine-patch editor (right-click a .png → "Create 9-Patch file"). You can also use any image editor to paint the guide pixels manually.

Modern alternatives

In Jetpack Compose, nine-patches are less commonly needed because:

  • Shape + Border + Shadow modifiers create scalable UI without bitmap images.
  • DrawablePainter can still display a nine-patch if needed for legacy assets.
  • Vector drawables (VectorPainter, Image(painter = painterResource(...))) scale to any size without quality loss and are now preferred for icons and simple shapes.
  • NinePatchDrawable is still used in View-based code where a designer provides a nine-patch asset.

Nine-patches remain relevant when a designer supplies a bitmap background with complex visual effects (gradients, shadows, textures) that are impractical to recreate in code, particularly in View-based screens.

↑ Back to top

Follow-up 1

How do you create a nine-patch image?

To create a nine-patch image, you can use the Draw 9-patch tool provided by the Android SDK. This tool allows you to define the stretchable and non-stretchable areas of the image by drawing black lines on the borders. The black lines indicate the areas that can be stretched, while the transparent areas indicate the non-stretchable parts. Once you have defined the areas, you can save the image as a PNG file and use it in your Android project.

Follow-up 2

What are the advantages of using nine-patch images?

There are several advantages of using nine-patch images in Android:

  1. Scalability: Nine-patch images can be scaled to fit different screen sizes and orientations without losing their shape or quality.
  2. Flexibility: They allow you to create custom UI elements that can adapt to different design requirements.
  3. Efficiency: Nine-patch images are lightweight and take up less memory compared to multiple images for different screen sizes.
  4. Consistency: They help maintain a consistent look and feel across different devices and screen densities.

Follow-up 3

Can you give an example of a scenario where a nine-patch image would be useful?

Sure! Let's say you have a button in your Android app that needs to have a custom background with rounded corners. Instead of creating multiple images for different screen sizes and orientations, you can create a single nine-patch image with stretchable areas defined around the corners. This way, the button will automatically adjust its size and shape based on the device's screen size and orientation, while still maintaining the rounded corners. This saves you time and effort in creating and managing multiple images for different devices.

3. Can you explain the different units of measurement used in Android UI design?

Android has a range of display densities across thousands of device models, so using the wrong unit of measurement causes layouts to look dramatically different on different screens. Knowing which unit to use where is a standard interview topic.

dp — density-independent pixels (use for layout dimensions)

dp (also written dip) is the standard unit for specifying view sizes, margins, padding, and any spatial dimension in a layout. 1 dp equals 1 physical pixel on a 160 dpi screen (the mdpi baseline). At higher densities, the system scales accordingly:

Density bucket DPI Scale factor 1 dp =
mdpi ~160 dpi 1 px
hdpi ~240 dpi 1.5× 1.5 px
xhdpi ~320 dpi 2 px
xxhdpi ~480 dpi 3 px
xxxhdpi ~640 dpi 4 px

Using dp ensures a button that is 48 dp wide appears roughly the same physical size on all devices, as recommended by Material Design's minimum touch target guidelines.

sp — scale-independent pixels (use for text sizes)

sp is identical to dp except it also respects the user's preferred text size set in system accessibility settings. Always use sp for android:textSize / fontSize. Never use dp for text — it prevents users with visual impairments from benefiting from large-text accessibility settings.

px — pixels (avoid in layouts)

Absolute physical pixels on the screen. Using px means your layout will appear much smaller on a high-density screen and much larger on a low-density screen. Only use px when you must work directly with the pixel buffer — for example, in a custom Canvas drawing operation where you need exact pixel measurements, using TypedValue.applyDimension() to convert dp to px at runtime.

Other units (rarely used)

  • in — physical inches. Rarely useful; devices report physical dimensions with varying accuracy.
  • mm — millimeters. Same caveats as in.
  • pt — points (1/72 of an inch). Rarely used on Android.

In Jetpack Compose

Compose uses the same underlying unit system but expresses values in Kotlin:

// dp
Modifier.padding(16.dp)
Modifier.size(48.dp)

// sp (text only)
Text(text = "Hello", fontSize = 16.sp)

The Dp and TextUnit (sp) types are separate in Compose, enforcing correct usage at the type level — you cannot accidentally pass a Dp where sp is expected.

Common gotcha: WindowManager.getDefaultDisplay() and similar APIs return pixel dimensions. Always convert to dp before using them in layout calculations to stay density-independent.

↑ Back to top

Follow-up 1

What is the difference between dp, sp, px, and in?

The difference between dp, sp, px, and in is as follows:

  • dp (density-independent pixels): This unit is a virtual pixel unit that is independent of the screen density. It is recommended for specifying dimensions in a layout.

  • sp (scaled pixels): This unit is similar to dp, but it is also scaled based on the user's preferred text size. It is recommended for specifying text sizes in a layout.

  • px (pixels): This unit represents the actual pixels on the screen. It is not recommended to use px for specifying dimensions in a layout, as it may result in inconsistent layouts on different screen densities.

  • in (inches): This unit represents physical inches on the screen. It is rarely used in Android UI design.

Follow-up 2

When would you use each unit?

You would use each unit in the following scenarios:

  • dp (density-independent pixels): Use dp when specifying dimensions in a layout, such as the width and height of views. This ensures that the dimensions are consistent across different screen densities.

  • sp (scaled pixels): Use sp when specifying text sizes in a layout. This allows the text to scale based on the user's preferred text size.

  • px (pixels): Avoid using px for specifying dimensions in a layout, as it may result in inconsistent layouts on different screen densities. However, you may need to use px when working with certain APIs or when performing pixel-level calculations.

  • in (inches): The use of inches as a unit of measurement is rare in Android UI design. It may be used in specific cases where physical dimensions need to be specified, such as when working with physical measurements or printing.

Follow-up 3

How does the Android system convert these units to actual pixel sizes?

The Android system converts these units to actual pixel sizes based on the device's screen density. The conversion is done using a formula that takes into account the device's screen density and the desired unit of measurement.

For dp and sp units, the conversion is based on the device's screen density. The formula used is:

pixels = dp * (screen density / 160)

For example, on a device with a screen density of 320 dpi, 1 dp will be equal to 2 pixels.

For px units, no conversion is performed as px represents the actual pixels on the screen.

For in units, the conversion is based on the device's screen density and the physical size of the screen. The formula used is:

pixels = in * screen density

It's important to note that the conversion to actual pixel sizes may result in rounding errors, so it's recommended to use dp and sp units for dimensions and text sizes in order to achieve consistent results across different devices.

4. What is a RecyclerView and how is it used?

RecyclerView is the standard widget for displaying large, scrollable lists and grids in the View-based UI system. In Jetpack Compose, LazyColumn and LazyRow serve the same purpose with a cleaner API, so new Compose-based code uses those instead. However, RecyclerView is still widely used in existing codebases and is an important interview topic.

Core concept

RecyclerView recycles (recycles) view holders as items scroll off screen, reusing them for new items that scroll into view. This keeps memory usage constant regardless of list size — a list of 10,000 items only ever has ~20 or so view objects alive at a time.

Key components

  • RecyclerView: the scrollable container widget placed in your layout.
  • RecyclerView.Adapter: supplies views for items. You override onCreateViewHolder() to inflate a view, onBindViewHolder() to bind data to it, and getItemCount() to report the list size.
  • RecyclerView.ViewHolder: caches references to views within an item, avoiding repeated findViewById calls on every bind.
  • LayoutManager: controls how items are arranged. LinearLayoutManager (vertical or horizontal list), GridLayoutManager (grid), StaggeredGridLayoutManager (Pinterest-style variable-height grid).
  • DiffUtil / ListAdapter: calculate the minimal set of changes when the data set updates, and animate only the changed items. ListAdapter wraps DiffUtil and is the modern way to write adapters — you call submitList() and it handles diffing on a background thread.

Modern usage with ListAdapter

class UserAdapter : ListAdapter(UserDiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        val binding = ItemUserBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return UserViewHolder(binding)
    }

    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    class UserViewHolder(private val binding: ItemUserBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(user: User) {
            binding.nameText.text = user.name
        }
    }
}

class UserDiffCallback : DiffUtil.ItemCallback() {
    override fun areItemsTheSame(old: User, new: User) = old.id == new.id
    override fun areContentsTheSame(old: User, new: User) = old == new
}

In Jetpack Compose

LazyColumn replaces RecyclerView and is simpler to use:

LazyColumn {
    items(users, key = { it.id }) { user ->
        UserItem(user = user)
    }
}

key parameter is important — it tells Compose which composable corresponds to which data item, enabling correct animations and state preservation during list updates.

Common interview questions

  • Why not use ListView? ListView is older and less efficient — it does not enforce view recycling and has no built-in DiffUtil support. RecyclerView replaced it.
  • What is the difference between notifyDataSetChanged() and DiffUtil? notifyDataSetChanged() redraws the entire list (no animations, expensive). DiffUtil calculates and animates only the changed items (insertions, removals, moves).
  • How do you handle click events on RecyclerView items? Pass a click lambda into the adapter or ViewHolder; avoid using android:onClick in item XML, which breaks item reuse.
↑ Back to top

Follow-up 1

What is the role of the ViewHolder in a RecyclerView?

The ViewHolder pattern is used in a RecyclerView to improve performance by caching references to the views in each item of the list. The ViewHolder holds references to the views so that they can be quickly accessed when binding data to the views. This avoids the need to repeatedly call findViewById() for each item, which can be expensive. By reusing the ViewHolder, the RecyclerView can efficiently recycle and bind data to the views as the user scrolls.

Follow-up 2

How does a RecyclerView handle item recycling?

A RecyclerView handles item recycling by reusing the views that are no longer visible on the screen. When an item scrolls off the screen, the RecyclerView detaches the corresponding ViewHolder and adds it to a pool of recycled views. When a new item needs to be displayed, the RecyclerView checks if there is a recycled view available in the pool. If there is, it binds the data to the recycled view and reattaches it to the RecyclerView. This recycling mechanism helps to improve performance and reduce memory usage.

Follow-up 3

What is the difference between a RecyclerView and a ListView?

The main difference between a RecyclerView and a ListView is that the RecyclerView provides more flexibility and control over the layout and animation of the list items. While a ListView uses a single type of view (usually TextView or ImageView) to display all the items, a RecyclerView can use multiple view types, allowing for more complex and customized layouts. Additionally, the RecyclerView has built-in support for item animations and item decorations, which can be easily customized.

Follow-up 4

How can you optimize a RecyclerView for better performance?

There are several ways to optimize a RecyclerView for better performance:

  1. Use the ViewHolder pattern: Implement the ViewHolder pattern to cache references to the views in each item, which avoids the need to repeatedly call findViewById() for each item.

  2. Implement item animations selectively: Use item animations sparingly, as they can impact performance. Only apply animations to items that really need them.

  3. Use the DiffUtil class: When updating the data set of the RecyclerView, use the DiffUtil class to calculate the difference between the old and new data sets. This allows for more efficient updates and reduces unnecessary layout calculations.

  4. Implement lazy loading: If you have a large data set, consider implementing lazy loading to load and display the data in chunks as the user scrolls. This can improve performance by reducing the initial load time.

  5. Optimize item layout: Avoid complex item layouts with nested views. Simplify the item layout as much as possible to improve performance.

5. Can you describe the different types of Android UI components like TextView, ImageView, etc.?

Android provides a rich set of UI components. In Jetpack Compose these are composable functions; in the View system they are View subclasses. Both are commonly used in production codebases.

Text display

  • TextView (View) / Text (Compose): displays text. Supports rich formatting, clickable spans, and HTML via Spannables in Views. In Compose, use AnnotatedString for styled text. Always use sp for font size.
  • EditText (View) / TextField / OutlinedTextField (Compose): accepts user input. In Views, set android:inputType to control the keyboard type (text, number, email, password). In Compose, TextField is fully stateful and follows the unidirectional data flow pattern.

Images

  • ImageView (View) / Image (Compose): displays images. For loading images from the network or disk, use Coil (Compose-first, Kotlin coroutines-based, recommended in 2026) or Glide/Picasso in View-based code. kotlin // Coil in Compose AsyncImage(model = url, contentDescription = "User avatar")

Buttons and selection

  • Button / MaterialButton (View) / Button (Compose): triggers an action. Material 3 in Compose provides Button, OutlinedButton, TextButton, ElevatedButton, and FilledTonalButton variants.
  • CheckBox (View) / Checkbox (Compose): binary on/off selection. In Compose, checkbox state is hoisted.
  • RadioButton + RadioGroup (View) / RadioButton (Compose): single selection from a group. In Compose, manage the selected value in a state holder.
  • Switch (View / Compose): toggle control. Material 3 provides an updated Switch composable.

Progress and loading

  • ProgressBar (View) / CircularProgressIndicator / LinearProgressIndicator (Compose): determinate (shows progress value) or indeterminate (spinning). Use for loading states.

Scrolling and lists

  • RecyclerView (View): the standard for large lists and grids in the View system. Uses Adapter + ViewHolder + LayoutManager.
  • LazyColumn / LazyRow / LazyVerticalGrid (Compose): Compose equivalents that compose items on demand as they scroll into view.
  • ScrollView / HorizontalScrollView (View): for simple scrollable content where RecyclerView is overkill. Not suitable for large datasets.
  • NestedScrollView (View): supports nested scrolling — used to scroll a layout that contains a fixed-height RecyclerView inside a CoordinatorLayout.

Navigation and structure

  • BottomNavigationView (View) / NavigationBar (Compose): Material Design bottom navigation bar for top-level destinations.
  • Toolbar / AppBarLayout (View) / TopAppBar (Compose): application toolbar with title, navigation icon, and actions.
  • ViewPager2 (View): horizontal swipe between pages (e.g., tabs, onboarding). In Compose, use HorizontalPager from the accompanist-pager / Compose Foundation library.

Dialogs and overlays

  • AlertDialog (View) / AlertDialog composable (Compose): modal confirmation dialogs. Material 3 provides styled variants.
  • Snackbar (View / Compose): brief feedback message that can include an action. In Compose, managed through SnackbarHostState inside a Scaffold.
  • BottomSheetDialogFragment (View) / ModalBottomSheet (Compose): swipe-up panel for additional options or content.

Common interview gotcha: interviewers often ask "how would you display a list of 1 million items?" The answer is RecyclerView with DiffUtil and a paged data source (Jetpack Paging 3), or LazyColumn with collectAsLazyPagingItems() in Compose — never load all items into memory at once.

↑ Back to top

Follow-up 1

How would you handle user interaction with these components?

To handle user interaction with Android UI components, you can use event listeners. Event listeners are interfaces that define methods to handle specific events. For example, to handle a button click, you can set an OnClickListener on the button and implement the onClick() method to perform the desired action.

Here's an example of how to handle a button click:

Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Perform action on button click
    }
});

You can also handle user interaction by using XML attributes like onClick in the layout file. This allows you to specify a method in your activity or fragment that will be called when the event occurs.


public void onButtonClick(View view) {
    // Perform action on button click
}

These are just a few examples of how you can handle user interaction with Android UI components. The specific approach will depend on the type of component and the desired behavior.

Follow-up 2

How can you customize the appearance of these components?

You can customize the appearance of Android UI components in several ways:

  1. XML attributes: Android provides a wide range of XML attributes that you can use to customize the appearance of UI components. For example, you can change the text color, background color, font size, etc.

  2. Styles and themes: Styles and themes allow you to define a set of attributes that can be applied to multiple UI components. By defining styles and themes, you can easily apply consistent appearance across your app.

  3. Custom drawables: You can create custom drawables to use as backgrounds, icons, or other visual elements for UI components. Custom drawables can be created using XML or programmatically.

  4. Custom views: If the built-in UI components don't meet your requirements, you can create custom views by extending existing views or creating entirely new views. Custom views give you full control over the appearance and behavior of the component.

These are just a few examples of how you can customize the appearance of Android UI components. The specific approach will depend on the component and the desired customization.

Follow-up 3

What are some common issues you might encounter when working with these components and how would you solve them?

When working with Android UI components, you might encounter some common issues such as:

  1. Performance issues: If you have a large number of UI components on the screen, it can impact the performance of your app. To solve this, you can use techniques like view recycling (e.g., RecyclerView) and optimizing layout hierarchies.

  2. Memory leaks: If you don't properly manage references to UI components, it can lead to memory leaks. To avoid memory leaks, make sure to release references to UI components when they are no longer needed.

  3. UI not updating: Sometimes, the UI doesn't update correctly when the underlying data changes. To solve this, you can use data binding libraries like LiveData or RxJava to automatically update the UI when the data changes.

  4. Inconsistent appearance: Different Android devices have different screen sizes and densities, which can result in inconsistent appearance of UI components. To ensure consistent appearance, you can use dimension and density-independent units, and test your app on different devices.

These are just a few examples of common issues you might encounter when working with Android UI components. The specific solution will depend on the nature of the issue and the specific component.

Live mock interview

Mock interview: Advanced Android UI

Intermediate ~5 min Your own free AI key

Your voice and your AI key never touch our servers; the key stays in this browser and is sent only to Google. Only your round scores are saved to track progress.