The Android Emulator, bundled with Android Studio, is usually the first thing to set up when testing an app across different device sizes and Android versions without owning a physical device for each.
Creating a virtual device
Android Studio → Device Manager → Create Device:
- Pick a hardware profile (Pixel 8, Pixel Tablet, etc.) — this determines screen size and resolution.
- Pick a system image — the Android version to run. Choosing one with Google Play included (not just "Google APIs") matters if your app depends on Play Services, or if you want to test installing from the Play Store itself.
- Name the AVD (Android Virtual Device) and finish.
# Or list/create from the command line
avdmanager list avd
avdmanager create avd -n Pixel8_API34 -k "system-images;android-34;google_apis_playstore;x86_64"Enabling hardware acceleration
The single biggest factor in emulator performance. On Intel/AMD machines, this means having Intel HAXM (older) or, on modern setups, the OS's built-in virtualization (Hyper-V on Windows, or the native hypervisor framework on macOS) enabled. Android Studio's Device Manager will warn you if acceleration isn't active — don't ignore that warning, since an unaccelerated emulator can be 5-10x slower.
On Apple Silicon Macs, use an arm64 system image rather than x86_64 — running x86 images requires translation and is noticeably slower than a native ARM image.
Common day-to-day commands
emulator -list-avds # list available virtual devices
emulator -avd Pixel8_API34 # launch a specific one
adb devices # confirm it's connected
adb install app-debug.apk # install an APK onto the running emulator
adb logcat # stream device logsSimulating real-world conditions
The emulator's Extended Controls panel (the "..." icon in the emulator toolbar) lets you simulate:
- GPS location changes — useful for testing location-based features without physically moving.
- Network conditions — throttle to simulate 3G speeds or high latency, surfacing loading-state bugs that only show up on slow connections.
- Battery state — test how the app behaves on low battery or while charging.
- Phone calls and SMS — simulate incoming calls/texts to test how the app handles interruptions.
| Aspect | Emulator | Physical device |
|---|---|---|
| Speed of iteration | Fast — no cable, snapshots available | Slower setup per test cycle |
| Manufacturer-specific behavior | Not replicated | Real, including OEM Android skins |
| Camera, biometrics, real touch latency | Simulated, not identical | Accurate |
| Best for | Everyday development iteration | Final pre-release verification |
When a physical device is still worth it
The emulator can't fully replicate manufacturer-specific behavior (especially on heavily customized Android skins), real camera/sensor input, actual touch latency, or genuine battery/thermal behavior. For final testing before a release — particularly anything involving the camera, biometrics, or performance under real-world conditions — testing on at least one or two physical devices catches issues the emulator won't.
A practical setup
For everyday development: one mid-range emulator profile (a Pixel with a recent-but-not-bleeding-edge API level) for fast iteration, plus one or two emulators at the extremes — the oldest API level you still support, and the newest — to catch version-specific behavior before it reaches a physical device or a release.
Cold boot vs. quick boot
By default, the emulator saves a snapshot of its running state when closed and resumes from it ("quick boot") the next time it launches — noticeably faster than a full boot, but occasionally the source of state-related weirdness (a stale background process, a cached network condition left on) that a genuine fresh boot would avoid:
emulator -avd Pixel8_API34 -no-snapshot-load # forces a real cold bootReaching for a cold boot specifically when debugging something that "used to work" or behaves inconsistently between runs is a quick way to rule out stale emulator state as the cause before assuming the app itself has a bug.
Testing different screen sizes and densities without new AVDs
Rather than creating a separate virtual device for every screen size worth testing, the Device Manager's Custom Hardware Profile option lets you adjust screen size and density directly on an existing AVD definition, or Android Studio's Resizable Emulator profile switches between phone, foldable, and tablet postures on a single running instance — useful for confirming a layout adapts correctly across form factors without maintaining a dozen separate AVDs just for screen-size coverage.
Running the emulator headless in CI
For automated UI tests, the emulator can run without a visible window, which is what makes device-based testing feasible inside a CI runner:
emulator -avd Pixel8_API34 -no-window -no-audio -gpu swiftshader_indirect-gpu swiftshader_indirect forces software rendering, since CI runners typically have no real GPU to pass through — slower than hardware acceleration, but the only option in most hosted CI environments, and adequate for functional UI tests that aren't measuring rendering performance itself.
Snapshots for fast, repeatable test states
Beyond the default quick-boot snapshot, the emulator can save named snapshots at any point — after logging in, after seeding specific app data — and reload straight to that exact state instead of repeating manual setup steps before every test run:
avdmanager # snapshots are managed via Android Studio's Snapshots pane,
# or "adb emu avd snapshot save <name>" from a running emulatorFor UI test suites specifically, starting every run from a saved "logged in, sample data seeded" snapshot instead of driving through login and data setup via the UI each time meaningfully cuts total test run time.
Testing on the emulator is only half the permission picture — see Android app permissions for how the runtime permission prompts you'll trigger during testing actually work from the user's side.
Common mistakes
- Choosing a system image without Google Play when the app depends on Play Services (push notifications via FCM, Google Sign-In, Maps) — these silently fail or crash on a Play-less image, which looks like an app bug but is actually an emulator configuration choice.
- Running an x86_64 image on Apple Silicon "because it was the first result" — it works, but noticeably slower than the native arm64 image, purely from unnecessary instruction translation.
- Ignoring Android Studio's acceleration warning and troubleshooting "slow emulator" elsewhere first — it's almost always the actual cause when present, and worth fixing before anything else.
- Testing exclusively on the emulator and skipping physical-device testing before release — camera, biometrics, and real touch latency are exactly the areas where emulator behavior diverges most from a real device.
Related reading
- Android App Permissions: A User's Guide to Staying Safe — shares tags: android (same category).
- Async Python with asyncio: A Practical Introduction — shares tags: programming.
- Big O Notation Without the Math Panic — shares tags: programming.
- Clean Code Principles That Actually Hold Up in Practice — shares tags: programming.
- Core Web Vitals Explained: What Actually Affects Your Score — shares tags: programming.