Android SharedPreferences Tutorial and Example

Recording Audio with MediaRecorder in Android

Audio capture looks deceptively easy in Android until you wire up your first recording button. MediaRecorder handles microphone input, encoding, and file output in one tidy class, which is why most voice memo and podcast apps rely on it. This guide walks through a working example, the permission flow modern Android demands, and the practical choices that affect file size and quality.

Australia's creator economy keeps growing, with listeners in Sydney and Melbourne topping global podcast charts each year. Whether you build a dictation tool for tradies in Brisbane, a language tutor for students in Perth, or a personal voice journal, the same building blocks apply. Picking the right combination of container and codec early saves refactoring later.

You will end up with a working record screen, an understanding of how MediaRecorder's state machine behaves, and a clear sense of when to switch to AudioRecord for lower-level work. A short comparison table near the end helps you pick the right API for your project.

How MediaRecorder Works in Android

MediaRecorder is stateful. It moves through Initial, Initialized, Prepared, Recording, Released, and Error states, and any call to the wrong method throws IllegalStateException. Setting the audio source, format, encoder, and output file must happen between Initial and Prepared, while start() and stop() toggle the Recording state.

The class is built for compressed output, so you always write to a file rather than a stream of raw samples. AAC inside an MP4 container is the common choice for high quality, while AMR_WB suits voice notes that must stay small. Match the audio source you pass to setAudioSource() to the microphones you expect to find on the target device.

For Australian developers shipping through Google Play, the default codecs cover most needs. If you need to capture both sides of a phone call for compliance, the platform restricts that source heavily, and lawful intercept scenarios are governed by the Australian Communications and Media Authority (ACMA).

Permissions and Manifest Setup

Audio capture on modern Android starts with the RECORD_AUDIO permission. Add it inside the <manifest> tag of your AndroidManifest.xml, and request it at runtime on API 23 or higher. The system prompt appears the first time the user taps record, so explain why the app needs the microphone before triggering the dialog.

Storage is the other gotcha. Scoped storage rules from Android 10 onward mean writing to public directories no longer works without MediaStore entries. For a private voice memo app, prefer the app-specific directory returned by getExternalFilesDir(), which keeps files inside the app sandbox and skips storage permission prompts. A folder like voice_notes/ is easy to clean up on app start.

If recordings ever leave the device, the Privacy Act 1988 and the Australian Privacy Principles (APPs) come into play. Even when data stays on the device, planning for eventual sync forces good habits. Documenting retention periods and giving users a clear deletion path keeps you aligned with the Office of the Australian Information Commissioner (OAIC) expectations.

Building a Minimal Recording UI

A recording screen can be a single button plus a timer, but separating visual state from recording state pays off. Use a Button that toggles between Start and Stop labels, a TextView for elapsed time, and a ProgressBar that pulses while MediaRecorder is active. Wrapping the recorder in a ViewModel survives configuration changes, which matters the moment a user rotates the phone mid-sentence.

Kotlin keeps the start sequence compact. After checking permission, you create the recorder, pick an audio source, output format, and encoder, set the output file, call prepare(), then start(). Catch IOException from prepare() and RuntimeException from start() to surface helpful messages rather than crashing the activity.

Updating the timer is a job for a Handler or a coroutine that posts to the main thread every second. Stop the timer and the recording together by calling stop() on the recorder, then reset the visual state. The pattern is reusable in any note-taking app, from a tradie's site journal in regional Queensland to a meditation guide built in a Sydney apartment.

Picking Audio Sources, Formats and Encoders

The audio source affects what the hardware delivers. MIC is the safest default and works on every handset. VOICE_RECOGNITION is tuned for speech-to-text pipelines. CAMCORDER is preferred when recording audio alongside video. Avoid VOICE_CALL on consumer builds; the platform blocks most variants, and ACMA-regulated environments are the only places where capturing the downlink is permitted.

For container formats, MPEG_4 is the workhorse. THREE_GPP works for tiny voice memos. AMR_WB inside THREE_GPP suits narrow-band voice notes sent over flaky 4G on a train between Geelong and Melbourne's Southern Cross station. AAC_ADTS inside MPEG_2_TS is rarely used outside broadcast workflows.

Encoder choice drives file size. AAC at 96 kbps delivers excellent speech quality for a podcast draft. AMR_NB produces tiny files but sounds compressed. Always call setAudioEncodingBitRate() and setAudioSamplingRate() explicitly, since OEM defaults differ between a Samsung Galaxy and a Pixel sold through Telstra or Optus.

Handling Lifecycle, Storage and Sharing

The recorder is bound to the lifecycle of whatever owns it. Always call release() in onStop or in the ViewModel's onCleared() so the microphone indicator disappears from the status bar. Forgetting release() is the most common reason an app's red mic dot lingers on a Pixel 8 after the user navigates away.

Saving files to getExternalFilesDir(DIRECTORY_MUSIC) is convenient, but plan for uploads too. Many apps queue recordings to a background worker and push them to a server. The pattern resembles any HTTP-driven feature, and the Volley HTTP tutorial walks through a similar setup that adapts cleanly to multipart audio uploads.

Once a file reaches the server, give the user a confirmation. In an Australian context, a small "Saved to cloud" toast with the local timestamp builds trust. If you monetise the app, remember that any subscription is subject to GST, so the back-end needs to capture that when audio is bundled into a paid tier.

Side-by-Side with AudioRecord and Other Approaches

MediaRecorder fits most use cases, but AudioRecord gives you raw PCM, which is what you need for real-time effects, spectrum analysis, or VoIP. The trade-off is complexity: you manage buffers, encoding, and file writing yourself. For a podcast editor on the move between Brisbane and the Gold Coast, MediaRecorder keeps the code lean; for a music production tool, AudioRecord is the only option.

Some teams prefer a REPL-style iteration cycle when prototyping audio pipelines. Tools that let you evaluate snippets interactively, such as a Magik REPL inside Emacs, can be handy for testing transformation logic before porting it to the Android codebase. The same principle of small, testable steps applies to recording state changes.

Here is a quick comparison so you can see the trade-offs at a glance.

Feature MediaRecorder AudioRecord MediaProjection + Audio
Output type Compressed file Raw PCM frames Compressed or PCM
Code complexity Low High High
Latency Higher Low Variable
Real-time processing No Yes Limited
API level 1+ 3+ 21+
Permission needed RECORD_AUDIO RECORD_AUDIO RECORD_AUDIO + MediaProjection
Typical use case Voice memos, podcasts VoIP, music apps Screen + audio capture

For most consumer apps in Australia, MediaRecorder is the right starting point. Reach for AudioRecord when latency or post-processing matters, and keep MediaProjection reserved for screen recorder use cases where the user explicitly opts in through the system prompt.