加载新片段时 Exoplayer 多个实例

Exoplayer multiple instances when loading new fragments

我正在为朋友开发一个广播流媒体应用程序。我决定走 Exo 玩家路线。一切正常,除非我加载一个新片段或转动屏幕。然后我得到一个新的 Exo 播放器实例,它在原来的播放器后面开始。它可能会变得非常混乱 - 我该如何避免这种情况?

这是我的代码。我使用以下方式打开片段:

 public View onCreateView(@NonNull LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState) {

    root = inflater.inflate(R.layout.fragment_home, container, false);

    initializeUIElements(root);


    return root;
}

我是这样称呼Exo播放器的:

private void initializeUIElements(View root) {

    playSeekBar = root.findViewById(R.id.progressBar1);
    playSeekBar.setMax(100);
    playSeekBar.setVisibility(View.INVISIBLE);





}


@Override
public void onStop() {
    super.onStop();
    if (Util.SDK_INT >= 24) {
        initializeMediaPlayer(root);
    }
}


private void initializeMediaPlayer(View root) {

    playerView = root.findViewById(R.id.video_view);
    player = new SimpleExoPlayer.Builder(getContext()).build();
    playerView.setPlayer(player);

    MediaItem media = MediaItem.fromUri(revurl);
    player.setMediaItem(media);

    player.setPlayWhenReady(playWhenReady);
    player.seekTo(currentWindow, playbackPosition);
    player.prepare();
}

@Override
public void onPause() {
    super.onPause();
    if (Util.SDK_INT < 24) {
        releasePlayer();
    }
}

@Override
public void onStart() {
    super.onStart();
    if (Util.SDK_INT >= 24) {
        initializeMediaPlayer(root);
    }
}

@Override
public void onResume() {
    super.onResume();

    if ((Util.SDK_INT < 24 || player == null)) {
        initializeMediaPlayer(root);
    }
}

@SuppressLint("InlinedApi")
private void hideUi() {
    playerView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
            | View.SYSTEM_UI_FLAG_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
private boolean playWhenReady = true;
private int currentWindow = 0;
private long playbackPosition = 0;


private void releasePlayer() {
    if (player != null) {
        playWhenReady = player.getPlayWhenReady();
        playbackPosition = player.getCurrentPosition();
        currentWindow = player.getCurrentWindowIndex();
        player.release();
        player = null;
    }
}

这是我打开的片段示例:

 public class FacebookFragment extends Fragment {

Context c;
private WebView mwebview;
private String url = "https://www.facebook.com/Revotionofdance";


public View onCreateView(@NonNull LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState) {

    View root = inflater.inflate(R.layout.facebook_fragment, container, false);
    mwebview = (WebView) root.findViewById(R.id.webview);
    mwebview.setWebViewClient(new WebViewClient());
    mwebview.addJavascriptInterface(new WebAppInterface(c), "Android");


    WebSettings webSettings = mwebview.getSettings();
    webSettings.setJavaScriptEnabled(true);
    mwebview.loadUrl(url);


    return root;
}

public class MyWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if ("https://www.facebook.com/Revotionofdance".equals(Uri.parse(url).getHost())) {
            // This is my website, so do not override; let my WebView load the page
            return false;
        }
        // Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        startActivity(intent);
        return true;
    }
}

public class WebAppInterface {
    Context mContext;

    /**
     * Instantiate the interface and set the context
     */
    WebAppInterface(Context c) {
        mContext = c;
    }

    /**
     * Show a toast from the web page
     */
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}

这是我的主要 activity 调用片段的地方:

  DrawerLayout drawer = findViewById(R.id.drawer_layout);
    NavigationView navigationView = findViewById(R.id.nav_view);
    // Passing each menu ID as a set of Ids because each
    // menu should be considered as top level destinations.
    mAppBarConfiguration = new AppBarConfiguration.Builder(
            R.id.nav_home, R.id.nav_facebook, R.id.nav_insta,R.id.nav_snap,R.id.nav_rodr)
            .setDrawerLayout(drawer)
            .build();
    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
    NavigationUI.setupWithNavController(navigationView, navController);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onSupportNavigateUp() {
    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    return NavigationUI.navigateUp(navController, mAppBarConfiguration)
            || super.onSupportNavigateUp();
}

如果您在整个应用程序中只有实例 ExoPlayer。您可以使用 singleton pattern 来提供实例 ExoPlayer。

如果您只想在每个片段中使用实例 Exoplayer。我建议您使用 ViewModel 来初始化和存储 ExoPlayer 实例,因为当您添加新片段或旋转屏幕时 ViewModel 不会被重置。

根据您上面的代码,您目前在 onStop() 方法中初始化了一个新的 SimpleExoPlayer 实例,而不是释放它。您根据 API 级别在 onStart() 或 onResume() 方法中初始化播放器,并在您的 onPause() 或 onStop() 方法中释放创建的播放器。

目前你有:

@Override
public void onStop() {
    super.onStop();
    if (Util.SDK_INT >= 24) {
        initializeMediaPlayer(root);
    }
}

改为:

@Override
  public void onStop() {
    super.onStop();
    if (Util.SDK_INT >= 24) {
      releasePlayer();
    }
  }