Android MediaPlayer错误(1,-19)规避方案及资源释放疑问
Hey there! Let's tackle this E/MediaPlayer: error (1, -19) issue you're facing. I've dealt with similar MediaPlayer headaches before, so let's break this down step by step based on your scenario.
First, let's clarify what that error means: Error (1,-19) almost always stems from invalid MediaPlayer state management—usually trying to load a new media source without properly cleaning up the old instance, or reusing an instance that's already been released. Since you're spawning new media files on every click (even if the previous one is still playing), not handling the old MediaPlayer correctly is the root cause here.
Here's your actionable fix plan:
1. Reuse a single MediaPlayer instance (don't create new ones every click)
Stop instantiating a new MediaPlayer in each onClick()—instead, declare a global instance in your Activity/Fragment. This way, you can control its state properly every time the user clicks:
package com.example.okunato.chance; // ... other imports ... public class YourActivity extends AppCompatActivity implements View.OnClickListener { // Global MediaPlayer instance private MediaPlayer mp3; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_layout); // Set click listener to your button/view findViewById(R.id.your_clickable_view).setOnClickListener(this); } @Override public void onClick(View v) { // Generate your random media source here (replace with your actual logic) Uri randomMediaUri = getRandomMediaUri(); // Handle existing MediaPlayer instance first if (mp3 != null) { if (mp3.isPlaying()) { mp3.stop(); // Stop current playback if ongoing } mp3.reset(); // Reset to idle state to load new source try { mp3.setDataSource(this, randomMediaUri); mp3.prepare(); // Prepare new source mp3.start(); } catch (IOException e) { e.printStackTrace(); } } else { // First click: create instance and start playback mp3 = MediaPlayer.create(this, randomMediaUri); mp3.start(); } } // Helper method for your random media logic private Uri getRandomMediaUri() { // Your existing random media generation code here return ...; } }
Note: MediaPlayer.create() automatically calls prepare(), so you don't need to do that for the first instance. For reset instances, you must call prepare() (or prepareAsync() for large files) before starting.
2. Properly release resources (don't just set mp3 = null randomly)
Setting mp3 = null without releasing first leaves the old instance holding system resources, which causes the error you're seeing. The correct place to clean up is when your component is destroyed:
@Override protected void onDestroy() { super.onDestroy(); if (mp3 != null) { if (mp3.isPlaying()) { mp3.stop(); } mp3.release(); // Free all system resources tied to this instance mp3 = null; // Nullify to avoid memory leaks } }
Never set mp3 = null in onClick() unless you're done using it entirely—this breaks state management and leads to orphaned instances.
3. Optional: Add a guard against rapid clicks (reduces state chaos)
Even if you don't care about audio overlap, rapid clicks can push MediaPlayer into invalid states. A simple flag can prevent this:
private boolean isMediaProcessing = false; @Override public void onClick(View v) { if (isMediaProcessing) return; isMediaProcessing = true; // ... existing MediaPlayer logic ... // Reset the flag when playback finishes mp3.setOnCompletionListener(mediaPlayer -> isMediaProcessing = false); }
4. Avoid common pitfalls
- Don't call
release()multiple times: Always checkmp3 != nullbefore any operation to avoid exceptions. - For large media files: Use
prepareAsync()instead ofprepare()to avoid blocking the main thread (ANR errors):mp3.reset(); mp3.setDataSource(this, randomMediaUri); mp3.prepareAsync(); mp3.setOnPreparedListener(mediaPlayer -> { mediaPlayer.start(); isMediaProcessing = false; });
Quick recap
The core fix is reusing one MediaPlayer instance, resetting its state on each click, and properly releasing it when your activity/fragment is destroyed. Your earlier mp3 = null was misplaced—only do that after calling release() in onDestroy().
内容的提问来源于stack exchange,提问作者Samuel Okunato

