Exoplayer Buffer状态会冻结UI?

时间:2018-08-07 16:59:08

标签: android service exoplayer

我正在使用Exoplayer开发在线无线电Android应用程序。

在我的PlayerActiivity中的onCreate()方法中,我初始化了media browser,从而启动了Music service

public class PlayerActiivity extends AppCompatActivity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
   initMediaBrowser();
}

protected void initMediaBrowser(){
   // Connect a media browser to get the media session token.
   mediaBrowser = new MediaBrowserCompat(this, new ComponentName(this, 
                MusicService.class), connectionCallback, null);
   }
}

音乐服务扩展了MediaBrowserServiceCompat

public class MusicService extends MediaBrowserServiceCompat {

@Override public void onCreate() {...}

@Override public int onStartCommand(Intent intent, int flags, int startId) {...}

...
}

当用户选择某个广播电台时,称为handlePlayRequest类的PlaybackManager方法被称为:

public class PlaybackManager implements Playback.Callback {

  public void handlePlayRequest() {
     serviceCallback.onPlaybackStart();
     playback.play(currentTrack);
  }
}

方法onPlaybackStart将媒体会话设置为活动状态并重新启动服务(由于MusicService已创建,因此仅调用onStartCommand

public void onPlaybackStart() {
 session.setActive(true);

 delayedStopHandler.removeCallbacksAndMessages(null);

 // The service needs to continue running even after the bound client (usually a
 // MediaController) disconnects, otherwise the music playback will stop.
 // Calling startService(Intent) will keep the service running until it is explicitly killed.
 startService(new Intent(getApplicationContext(), MusicService.class));
}

方法play获取当前的音乐曲目,并准备播放器进行播放:

@Override
public void play(QueueItem item) {
   playOnFocusGain = true;
   tryToGetAudioFocus();
   registerAudioNoisyReceiver();
   String mediaId = item.getDescription().getMediaId();
   boolean mediaHasChanged = !TextUtils.equals(mediaId, currentMediaId);
   if (mediaHasChanged) {
       currentMediaId = mediaId;
       if(mediaProvider != null){
           mediaProvider.setCurrentPlayerMediaId(currentMediaId);
       }
       LogHelper.d(TAG, "change current mediaId to: " + mediaId);
   }

   if (mediaHasChanged || exoPlayer == null) {
       releaseResources(false); // release everything except the player

       Track track = null;
       if(mediaProvider != null){
           track = mediaProvider.getTrack(item.getDescription().getMediaId());
       }

       String source;

       if(track == null){
           if (callback != null) {
               callback.onError("Player error " + " track with media id: " + item.getDescription().getMediaId() + " was not found");
           }
           LogHelper.e(TAG, "Player error " + " track with media id: " + item.getDescription().getMediaId() + " was not found");
           return;
       }
       source = track.getStreamUrl();

       if (source != null) {
          source = source.replaceAll(" ", "%20"); // Escape spaces for URLs
       }

       if (exoPlayer == null) {

           DefaultAllocator allocator =
               new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE);

           DefaultLoadControl defaultLoadControl = new DefaultLoadControl(
               allocator,
               MIN_BUFFER_MS,
               MAX_BUFFER_MS,
               DEFAULT_BUFFER_FOR_PLAYBACK_MS,
               DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS,
               DEFAULT_TARGET_BUFFER_BYTES,
               DEFAULT_PRIORITIZE_TIME_OVER_SIZE_THRESHOLDS
               );

           exoPlayer = ExoPlayerFactory.newSimpleInstance(
               new DefaultRenderersFactory(context),
               new DefaultTrackSelector(), defaultLoadControl);
           exoPlayer.addListener(eventListener);
       }

       final AudioAttributes audioAttributes = new AudioAttributes.Builder()
           .setContentType(CONTENT_TYPE_MUSIC)
           .setUsage(USAGE_MEDIA)
           .build();

       exoPlayer.setAudioAttributes(audioAttributes);

       // Produces DataSource instances through which media data is loaded.
       DataSource.Factory dataSourceFactory =
               new DefaultDataSourceFactory(
                   context, Util.getUserAgent(context,
                   context.getResources().getString(R.string.app_name)), null);

       MediaSource mediaSource;
       if (track.isHlsStream()) {
           mediaSource = new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(
               Uri.parse(source));
       } else {
           mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(
               Uri.parse(source));
       }

       // Prepares media to play (happens on background thread) and triggers
       // {@code onPlayerStateChanged} callback when the stream is ready to play.
       exoPlayer.prepare(mediaSource);

       // If we are streaming from the internet, we want to hold a
       // Wifi lock, which prevents the Wifi radio from going to
       // sleep while the song is playing.
       wifiLock.acquire();
   }

   configurePlayerState();
}

方法configurePlayerState开始播放媒体内容:

private void configurePlayerState() {
   LogHelper.d(TAG, "configurePlayerState. currentAudioFocusState=", currentAudioFocusState);
   if (currentAudioFocusState == AUDIO_NO_FOCUS_NO_DUCK) {
       // We don't have audio focus and can't duck, so we have to pause
       pause();
   } else {
       registerAudioNoisyReceiver();

       if (currentAudioFocusState == AUDIO_NO_FOCUS_CAN_DUCK) {
           // We're permitted to play, but only if we 'duck', ie: play softly
           exoPlayer.setVolume(VOLUME_DUCK);
       } else {
           exoPlayer.setVolume(VOLUME_NORMAL);
       }

       // If we were playing when we lost focus, we need to resume playing.
       if (playOnFocusGain) {
           LogHelper.d("LocalPlayback", "PLAY!");
           exoPlayer.setPlayWhenReady(true);
           playOnFocusGain = false;
           if(!mediaProvider.isTrackPlayed()){
               callback.onTrackPlayed(true);
           }
       }
   }
}

执行configurePlayerState后,Exoplayer进入缓冲状态。

onPlayerStateChanged调用方法playbackState == Player.STATE_BUFFERING

public final class LocalPlayback implements Playback {
@Override
        public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
            switch (playbackState) {
                case Player.STATE_IDLE:
                case Player.STATE_BUFFERING:
                case Player.STATE_READY:
                    if (callback != null) {
                        callback.onPlaybackStatusChanged(getState());
                    }
                    break;
                case Player.STATE_ENDED:
                    // The media player finished playing the current song.
                    if (callback != null) {
                        callback.onCompletion();
                    }
                    break;
            }
        }

}

在Exoplayer转到“缓冲”之后,UI冻结。在我的Motorola(Moto X Play)和Nexus(Nexus 5X)设备上,冻结持续约3秒。在客户端设备上,冻结持续的时间更长。

只有在通过onPlayerStateChanged调用了回调playbackState == Player.STATE_READY之后,UI冻结才结束。

  

问题:在exoplayer保持缓冲状态时如何避免UI冻结?

我的依赖项:

android {
 compileSdkVersion 27
 defaultConfig {
   applicationId "com.app"
   minSdkVersion 16
   targetSdkVersion 27
   multiDexEnabled true
   buildToolsVersion '27.0.3'
 }

 buildTypes {
   ...
 }

 compileOptions {
   sourceCompatibility JavaVersion.VERSION_1_8
   targetCompatibility JavaVersion.VERSION_1_8
 }
}

dependencies {
 ...
 compile 'com.google.android.exoplayer:exoplayer-core:2.7.3'
 compile 'com.google.android.exoplayer:exoplayer-hls:2.7.3'  
}

0 个答案:

没有答案