加载新片段时 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();
}
}
我正在为朋友开发一个广播流媒体应用程序。我决定走 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();
}
}