2013-04-24 10 views
13

mój plik xml:powierzchnia została wydana przy próbie setDisplay do MediaPlayer

<SurfaceView 
    android:id="@+id/surfaceView" 
    android:layout_marginTop="50dp" 
    android:layout_width="fill_parent" 
    android:layout_height="300dp" /> 

moją funkcję setDisplay:

public void playVideo() { 
    MediaPlayer mp = new MediaPlayer(); 
    SurfaceView sv = (SurfaceView) this.findViewById(R.id.surfaceView); 
    try { 
     mp.setDataSource("sdcard/test/a.3gp"); 
     SurfaceHolder sh = sv.getHolder(); 
     mp.setDisplay(sh);***----the exception occured here*** 
     mp.prepare(); 
     mp.start(); 
    } catch (IllegalArgumentException e) { 
     e.printStackTrace(); 
    } catch (SecurityException e) { 
     e.printStackTrace(); 
    } catch (IllegalStateException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

dziennik jak poniżej:

04-24 22:19:33.645: W/System.err(16106): java.lang.IllegalArgumentException: The surface has been released 
04-24 22:19:33.645: W/System.err(16106): at android.media.MediaPlayer._setVideoSurface(Native Method) 
04-24 22:19:33.645: W/System.err(16106): at android.media.MediaPlayer.setDisplay(MediaPlayer.java:698) 

Znalazłem kilka podobnych pytań tutaj, ale wszystkie te nie są dla mnie odpowiednie. Czekam na twoje odpowiedzi. Dziękuję bardzo.

Odpowiedz

12

Powierzchnia może zostać zniszczona. Dlatego trzeba dodać do menu a public void surfaceDestroyed(SurfaceHolder holder) do realizacji Twojego SurfaceView jest tak:

@Override 
public void surfaceDestroyed(SurfaceHolder holder) { 
    synchronized (this) { 
     hasActiveHolder = false; 

     synchronized(this)   { 
       this.notifyAll(); 
     } 
    } 
} 

Należy również dodać funkcję, która obsługuje tworzenie powierzchni:

@Override 
public void surfaceCreated(SurfaceHolder holder) { 
    synchronized (this) { 
     hasActiveHolder = true; 
     this.notifyAll() 
    } 
} 

I zmodyfikuj własną funkcję w następujący sposób:

mp.setDataSource("sdcard/test/a.3gp"); 
    SurfaceHolder sh = sv.getHolder(); 
    synchronized (this) { 
     while (!hasActiveHolder) { 
       try { 
        this.wait(); 
       } catch (InterruptedException e) { 
       //Print something 
       } 
     } 
     mp.setDisplay(sh); 
     mp.prepare(); 
    } 

Masz inną opcję, która jest sposobem, w jaki Google sugeruje użycie SurfaceView: w osobnym wątku.

+1

Próbowałem tego, co mówisz, ale to nie działa, a ekran wstrzymania staje się czarny. Oczekiwanie na więcej informacji. Bardzo dziękuję za odpowiedź. – Cooosuper

+0

Właśnie zauważyłem, że w SurfaceDestroyed umieszczam zsynchronizowane w synchronizowanym bloku tego samego obiektu. Usuń drugi. Wygląda na to, że utknąłeś w oczekiwaniu. Sugeruję, że jeśli to nie zadziała, dołączasz debugger i wstrzymujesz wszystkie wątki, które widzisz, aby znaleźć wątek, który czeka() – EyalBellisha

+3

Próbowałem innego sposobu, aby to naprawić. Przenoszę 'setDisplay' do Callback, gdy powierzchnia została utworzona ("surfaceCreated"). Bardzo dziękuję za odpowiedź! – Cooosuper

8

To coś związane z kolejnością wykonywania, ponieważ powierzchnia musi być stworzony przed ustawieniem wyświetlacz dla MediaPlayer, so you have to override the callback method surfaceCreated` do poniższego:

@Override 
public void surfaceCreated(SurfaceHolder holder) { 
    mp.setDisplay(sh); // now "mp" is defined as a class variable 
} 

i teraz nie ma potrzeby, aby setDisplay wewnątrz sposób odtwarzania:

private MediaPlayer mp; // to use it inside surfaceCreated callback method 
public void playVideo() { 
    mp = new MediaPlayer(); 
    SurfaceView sv = (SurfaceView) this.findViewById(R.id.surfaceView); 
    try { 
     mp.setDataSource("sdcard/test/a.3gp"); 
     SurfaceHolder sh = sv.getHolder(); 
     mp.prepare(); 
     mp.start(); 
    } catch (IllegalArgumentException e) { 
     e.printStackTrace(); 
    } catch (SecurityException e) { 
     e.printStackTrace(); 
    } catch (IllegalStateException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 
0

Najprostszym sposobem jest po prostu zadzwonić setDisplay w surfaceCreated:

@Override 
public void surfaceCreated(SurfaceHolder holder) { 
    mp.setDisplay(holder) 
} 

i nie zapomnij, aby rozpiąć powierzchni:

@Override 
public void surfaceDestroyed(SurfaceHolder holder) { 
    mp.setDisplay(null); 
} 

Uwaga: odtwarzacz multimedialny powinien być inicjowane gdzieś wcześniej, na przykład w onCreate.

1

Dla tych nadal występują problemy, spróbuj wykonawczych SurfaceHolder.Callback w swojej działalności/fragment/etc i na onCreate/onCreateView metody, zadzwoń (oddzwanianie SurfaceHolder.Callback) addCallback metodę, za pomocą swojego aktywność/fragment/etc jako wywołanie zwrotne parametru.

0

Użyj funkcji SurfaceHolder.Callback jak poniżej

SurfaceView mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView); 
SurfaceHolder holder = mSurfaceView.getHolder(); 
final MediaPlayer player = new MediaPlayer(); 

holder.addCallback(new SurfaceHolder.Callback() { 
    @Override 
    public void surfaceCreated(SurfaceHolder holder) { 
     player.setDisplay(holder); 
    } 

    @Override 
    public void surfaceChanged(SurfaceHolder holder, int format, int width, 
    int height) { 

    } 

    @Override 
    public void surfaceDestroyed(SurfaceHolder holder) { 

    } 
}); 

String UrlPath="android.resource://"+getActivity().getPackageName()+"/"+R.raw.your_file_name_without_extension; 
try { 
    player.setDataSource(getActivity(),Uri.parse(UrlPath)); 
    player.prepareAsync(); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 

    @Override 
    public void onPrepared(MediaPlayer mp) { 
     mp.start(); 
    } 
}); 
0

Możemy spojrzeć na kod źródłowy VideoView:

SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback(){ 
... 
    public void surfaceCreated(SurfaceHolder holder) 
    { 
     mSurfaceHolder = holder; 
     openVideo(); 
    } 
    private void openVideo() { 
     ... 
     mMediaPlayer = new MediaPlayer(); 
     mMediaPlayer.setDisplay(mSurfaceHolder); 
    } 
} 

Więc możemy dowiedzieć się, że powinniśmy używać mediaplayer.setDisplay() w surfaceCreate metody nazwać.

Powiązane problemy