0

現在搜索幾天,無法找出mediaPlayer爲什麼隨着設備的方向改變隨機觸發onCompletion。看起來像更強大的平板電腦更多的內存設備崩潰不是很頻繁,但有時他們也會這樣做。Android隨機調用mediaPlayer onCompletion,改變流媒體rtsp視頻的方向變化

我的MediaPlayer運行在Fragment中,我嘗試使用持久的MediaPlayer技術調用setRetainInstance(true)。

作爲一個提示,有些設備有時在LogCat中表示,在發生這種情況時,主線程中正在做太多工作。

這裏是我的代碼片段:

final public class MediaPlayerFragment extends Fragment implements OnCompletionListener, OnPreparedListener, OnBufferingUpdateListener, OnInfoListener, OnErrorListener, SurfaceHolder.Callback { 

    /** 
    * 
    */ 
    public final static String TAG     = "MediaPlayerFragment"; 

    private MediaPlayer   mp     = null; 
    private SurfaceView   surfaceView   = null; 
    private String    path; 

    // create an handler 
    private final Handler  myHandler   = new Handler(); 

    private static final double ASPECT_RATIO  = 4.0/3.0; 

    /** 
    * Update the ui, so that background tasks can call this update on ui thread 
    */ 
    final Runnable    updateUIRunnable = new Runnable() { 
                 @Override 
                 public void run() { 
                  MediaPlayerFragment.this.updateSurfaceSizeToLayout(); 
                 } 
                }; 

    @Override 
    public void onCreate(final Bundle savedInstanceState) { 
     Log.v(MediaPlayerFragment.TAG, "INFO: onCreate"); 
     super.onCreate(savedInstanceState); 

     // Control whether a fragment instance is retained across Activity 
     // re-creation 
     this.setRetainInstance(true); 

     // get the extra data from the Intent (Container) 
     this.path = this.getArguments().getString("path"); 
     if (this.path == null) 
      throw new RuntimeException("No path where passed to the mediaplayerFragment"); 
    } 

    /** 
    * onCreateView 
    * 
    * Setup the view of the media player with a surface to show the mediaPlayer 
    */ 
    @Override 
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { 
     Log.v(MediaPlayerFragment.TAG, "INFO: onCreateView"); 

     this.surfaceView = new SurfaceView(this.getActivity()); 

     // Push surfaceView to maximum available space 
     final android.widget.FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 
     this.surfaceView.setLayoutParams(layoutParams); 

     // Placeholder for the area of the video, region to display 
     final SurfaceHolder surfaceHolder = this.surfaceView.getHolder(); 
     surfaceHolder.addCallback(this); 
     surfaceHolder.setSizeFromLayout(); 

     return this.surfaceView; 
    } 

    @Override 
    public void onPause() { 
     Log.v(MediaPlayerFragment.TAG, "onPause()"); 

     if (this.mp != null) { 
      this.mp.pause(); 
      this.mp.setDisplay(null); 
     } 

     super.onPause(); 
    } 

    /** 
    * Prepare the media player for playback. This sets the filepath and start 
    * the buffering for the player 
    */ 
    private void preparePlayer() { 

     Log.v(MediaPlayerFragment.TAG, "preparePlayer"); 

     try { 
      this.mp.setLooping(false); 
      this.mp.setDataSource(this.path); 
      this.mp.prepareAsync(); 

     } 
     catch (final IOException e) { 
      Log.e(MediaPlayerFragment.TAG, "ERROR: Caught ioExeption" + e.getMessage(), e); 
     } 
     catch (final Exception e) { 
      // IllegalStateException if it is called in an invalid state 
      Log.e(MediaPlayerFragment.TAG, "ERROR: " + e.getMessage(), e); 
     } 
    } 

    @Override 
    public void onCompletion(final MediaPlayer arg0) { 
     Log.d(MediaPlayerFragment.TAG, "onCompletion called"); 

     this.releaseMediaPlayer(); 
    } 

    @Override 
    public void onPrepared(final MediaPlayer mediaplayer) { 
     Log.d(MediaPlayerFragment.TAG, "onPrepared called"); 

     if (!this.mp.isPlaying()) { 
      this.mp.start(); 
     } 
    } 

    @Override 
    public boolean onError(final MediaPlayer arg0, final int arg1, final int arg2) { 
     Log.v(MediaPlayerFragment.TAG, "onError MediaPlayer"); 

     return false; 
    } 

    /** 
    * Release the media player object and set its variable to null. 
    */ 
    private void releaseMediaPlayer() { 
     if (this.mp != null) { 
      this.mp.reset(); 
      this.mp.release(); 
      this.mp = null; 
     } 
    } 

    /** 
    * display is turned 
    */ 
    @Override 
    public void surfaceCreated(final SurfaceHolder holder) { 
     if (this.mp == null) { 
      // get a MediaPlayer to display the video 
      // store the MediaPlayer in the Application, so it does not get 
      this.mp = new MediaPlayer(); 
      this.mp.setOnCompletionListener(this); 
      this.mp.setOnPreparedListener(this); 
      this.mp.setOnBufferingUpdateListener(this); 
      this.mp.setOnInfoListener(this); 
      this.mp.setOnErrorListener(this); 
      this.mp.setScreenOnWhilePlaying(true); 

      this.mp.setDisplay(holder); 

      this.preparePlayer(); 
     } else { 
      // re-establish connection to given surfaceHolder 
      this.mp.setDisplay(holder); 
     } 
    } 

    @Override 
    public void surfaceDestroyed(final SurfaceHolder surfaceHolder1) { 
     Log.v(MediaPlayerFragment.TAG, "surfaceDestroyed called"); 

     // disengage old surface holder 
     if (this.mp != null) { 
      this.mp.setDisplay(null); 
     } 
    } 

    /** 
    * This is called immediately after any structural changes (format or size) 
    * have been made to the surface. You should at this point update the 
    * imagery in the surface. This method is always called at least once, after 
    * surfaceCreated(SurfaceHolder). 
    * 
    * @param holder 
    *   The SurfaceHolder whose surface has changed. 
    * @param format 
    *   The new PixelFormat of the surface. 
    * @param width 
    *   The new width of the surface. 
    * @param height 
    *   The new height of the surface. 
    */ 
    @Override 
    public void surfaceChanged(final SurfaceHolder holder, final int format, final int width, final int height) { 
     Log.v(MediaPlayerFragment.TAG, "surfaceChanged called"); 

     // disengage old surface holder 
     if (this.mp != null) { 
      this.myHandler.post(this.updateUIRunnable); 
      this.mp.setDisplay(holder); 
     } 
    } 

    /** 
    * The looks at the dimensions of the surfaceView that holds the MediaPlayer 
    * (Video) and update the size of it to fit that dimension. This is 
    * necessary because of orientation changes that alters the possible height 
    * and width of the surface on that the video is drawn. 
    */ 
    @SuppressWarnings("boxing") 
    public void updateSurfaceSizeToLayout() { 
     // Surface.ROTATION_0 (no rotation), Surface.ROTATION_90, 
     // Surface.ROTATION_180, or Surface.ROTATION_270 
     final int orientation = this.getResources().getConfiguration().orientation; 

     Log.d(MediaPlayerFragment.TAG, "Orientation :" + orientation); 

     // Get the SurfaceView layout parameters 
     final android.view.ViewGroup.LayoutParams lp = this.surfaceView.getLayoutParams(); 

     final FrameLayout frameLayout = (FrameLayout) this.surfaceView.getParent(); 
     final int width = frameLayout.getWidth(); 
     final int height = frameLayout.getHeight(); 

     if (orientation == android.content.res.Configuration.ORIENTATION_PORTRAIT) { 
      // Display in portrait 
      lp.width = LayoutParams.MATCH_PARENT; 
      lp.height = (int) (width/MediaPlayerFragment.ASPECT_RATIO); 
      Log.d(MediaPlayerFragment.TAG, String.format("New surfaceView size: width:max ,height:%d", lp.height)); 
     } else { 
      lp.width = (int) (height * MediaPlayerFragment.ASPECT_RATIO); 
      lp.height = LayoutParams.MATCH_PARENT; 
      Log.d(MediaPlayerFragment.TAG, String.format("New surfaceView size: width:%d , height: max", lp.width)); 
     } 

     // Commit the layout parameters 
     this.surfaceView.setLayoutParams(lp); 
     this.surfaceView.getHolder().setSizeFromLayout(); 
    } 
} 

任何人都可以看到我是如何處理MediaPlayer的surfaceView或別的東西,使應用程序崩潰一個極大的錯誤。

這裏是logcat的日誌後,將其旋轉兩次,在第二取向變化墜毀:

09-02 18:59:05.796: W/MediaPlayer(19521): info/warning (702, 0) 
09-02 18:59:05.806: D/MediaPlayerFragment(19521): MediaPlayer.OnInfoListener: what:702, extra:0 
09-02 18:59:05.836: W/MediaPlayer(19521): info/warning (701, 0) 
09-02 18:59:05.836: D/MediaPlayerFragment(19521): MediaPlayer.OnInfoListener: what:701, extra:0 
09-02 18:59:06.356: V/MediaPlayerFragment(19521): DEBUG: onPause 
09-02 18:59:06.436: V/MediaPlayerFragment(19521): surfaceDestroyed called 
09-02 18:59:06.466: V/MediaPlayerFragment(19521): onDetach 
09-02 18:59:06.546: D/MPActivity(19521): onCreate 
09-02 18:59:06.546: V/MediaPlayerFragment(19521): DEBUG: onAttach 
09-02 18:59:06.596: D/MPActivity(19521): addVideoFragment 
09-02 18:59:06.596: V/MediaPlayerFragment(19521): INFO: onCreateView 
09-02 18:59:06.606: V/MediaPlayerFragment(19521): DEBUG: onResume 
09-02 18:59:06.696: D/MediaPlayerFragment(19521): surfaceCreated called 
09-02 18:59:06.726: V/MediaPlayerFragment(19521): surfaceChanged called 
09-02 18:59:06.796: D/MediaPlayerFragment(19521): Orientation :2 
09-02 18:59:06.796: D/MediaPlayerFragment(19521): width:810 ,height:-1 
09-02 18:59:06.826: V/MediaPlayerFragment(19521): surfaceChanged called 
09-02 18:59:06.906: D/MediaPlayerFragment(19521): Orientation :2 
09-02 18:59:06.916: D/MediaPlayerFragment(19521): width:810 ,height:-1 
09-02 18:59:07.886: W/MediaPlayer(19521): info/warning (702, 0) 
09-02 18:59:07.886: D/MediaPlayerFragment(19521): MediaPlayer.OnInfoListener: what:702, extra:0 
09-02 18:59:08.186: W/MediaPlayer(19521): info/warning (701, 0) 
09-02 18:59:08.186: D/MediaPlayerFragment(19521): MediaPlayer.OnInfoListener: what:701, extra:0 
09-02 18:59:09.036: V/MediaPlayerFragment(19521): DEBUG: onPause 
09-02 18:59:09.056: V/MediaPlayerFragment(19521): surfaceDestroyed called 
09-02 18:59:09.066: V/MediaPlayerFragment(19521): onDetach 
09-02 18:59:09.086: E/MediaPlayer(19521): error (1, -2147483648) 
09-02 18:59:09.086: D/MPActivity(19521): onCreate 
09-02 18:59:09.086: V/MediaPlayerFragment(19521): DEBUG: onAttach 
09-02 18:59:09.116: D/MPActivity(19521): addVideoFragment 
09-02 18:59:09.116: V/MediaPlayerFragment(19521): INFO: onCreateView 
09-02 18:59:09.126: V/MediaPlayerFragment(19521): DEBUG: onResume 
09-02 18:59:09.176: D/MediaPlayerFragment(19521): surfaceCreated called 
09-02 18:59:09.196: V/MediaPlayerFragment(19521): surfaceChanged called 
09-02 18:59:09.196: E/MediaPlayer(19521): Error (1,-2147483648) 
09-02 18:59:09.196: V/MediaPlayerFragment(19521): onError MediaPlayer 
09-02 18:59:09.196: D/MediaPlayerFragment(19521): onCompletion called 
09-02 18:59:09.366: V/MediaPlayerFragment(19521): surfaceDestroyed called 
09-02 18:59:09.376: D/MediaPlayerFragment(19521): Orientation :1 
09-02 18:59:09.376: D/MediaPlayerFragment(19521): width:-1 ,height:600 
09-02 18:59:09.376: V/MediaPlayerFragment(19521): DEBUG: onPause 
09-02 18:59:09.396: D/VideoListActivity(19521): onResume() 
09-02 18:59:09.496: V/MediaPlayerFragment(19521): INFO: onDestroy 
09-02 18:59:09.496: V/MediaPlayerFragment(19521): onDetach 
+0

請發表您的logcat – MrEngineer13 2014-09-02 16:51:39

回答

0

關於OnCompletionListener 這是一個典型的錯誤發生在一些三星設備。要克服它,唯一的方法就是保持標準播放器正在檢查視頻資產的長度,如果當前位置沒有接近尾聲,則應忽略OnCompletion事件。

關於setRetainInstance(true): 當這個方法被調用時,片段的生命週期將是: 的onCreate(只有一次,無論多少次旋轉) onCreateView(每個設備旋轉時間) - 在這裏,所有的意見都重新,所以你的表面,你的持有人在這一點上是無效的。 etc ...

看看這個POC我創建了允許旋轉。 How to play audio continuously while orientation changes in Android?

好運

+0

多少密切? – Caipivara 2015-11-12 04:30:36