在Android中使用YouTube API的最佳方式是什么? [英] What is the best way of using Youtube API in Android?
问题描述
我想在我的Android应用程序中实现YouTube API,但有一些限制。
播放/暂停按钮应可见。(默认样式和最小样式都支持此功能)
时间栏应可见且可操作。(在最小样式的情况下,时间栏仅可见,但点击它不会产生任何效果)
用户不应该能够直接共享视频或打开YouTube应用程序。(在本例中,默认为不是选项)
最小样式可以完美地工作,但时间栏不起作用。我曾考虑使用自定义Seekbar,但当视频处于全屏模式时它是不可见的。有什么建议吗?
推荐答案
YouTube API面临的两个主要问题是:
1.将YoutubePlayerStlye设置为最小样式时,无法访问搜索栏(时间栏)。
2.视频末尾会弹出相关视频。
1的解决方案:
因此,我们必须构建一个自定义搜索栏来访问时间进度,并根据需要更新(拖动)搜索栏上的时间。但YoutubePlayer不允许在视频上方/顶部显示视图(窗口小部件),如果发生这种情况,您会暂停视频。 因此,解决方案是在youtubePlayer下面绘制一个自定义搜索栏。 我们可以通过以下布局实现这一点:youtube_player_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:gravity="center"
android:orientation="vertical"
tools:context=".features.video.YoutubePlayerActivity">
<!-- youtube player view to play videos -->
<com.google.android.youtube.player.YouTubePlayerView
android:id="@+id/youtube_player_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/black"
android:focusable="true" />
<!-- Full layout of seekbar, you can also use a constraintLayout-->
<LinearLayout
android:id="@+id/video_control_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@android:color/black"
android:gravity="center"
android:orientation="horizontal">
<!-- Seekbar to display video progress -->
<SeekBar
android:id="@+id/video_seekbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:layout_weight="6"
android:max="100"
android:progress="0" />
<!-- Time display -->
<TextView
android:id="@+id/play_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:gravity="center"
android:text="--:--"
android:textColor="@android:color/white" />
<!-- FullScreen button -->
<ImageButton
android:id="@+id/bt_fullscreen"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:src="@drawable/ic_fullscreen" />
</LinearLayout>
</LinearLayout>
纵向视图:
景观:
此自定义搜索栏还包含一个全屏按钮(ImageButton),您可以在更改方向时从Kotlin/Java代码上的矢量资源句柄添加该按钮。
2的解决方案: 我在网上找到的常见解决方案是在视频结束时将seakTime设置为零。
@Override
public void onVideoEnded() {
if (null == mPlayer) return;
mPlayer.seekToMillis(0);
mPlayer.pause();
}
但此解决方案不是最佳,因为即使您使用它,相关视频有时也会播放半秒,这看起来并不理想。
所以简单的解决方案是永远不要让视频结束,这样在结束时就不会显示相关的视频。要实现这一点,我们必须在视频结束前停止~1.2秒(我认为可以从视频中牺牲~1.2秒,但这取决于用法)。
if (null == mPlayer) return;
if (mPlayer.getCurrentTimeMillis() >= (mPlayer.getDurationMillis() - 1200L)) {
mPlayer.seekToMillis(0);
mPlayer.pause();
}
我还发布了youtubePlayer的完整Java代码。
YoutubePlayerActivity.java
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.content.ContextCompat;
import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayerView;
import com.syncnicia.theguideapp.R;
public class YoutubePlayerActivity extends YouTubeBaseActivity {
private static final String TAG = "YoutubePlayerActivity";
private String videoID;
private YouTubePlayerView youTubePlayerView;
private TextView mPlayTimeTextView;
private YouTubePlayer mPlayer;
private Handler mHandler = null;
private SeekBar mSeekBar;
private ImageButton btFullScreen;
private int seekTime = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_youtube_player);
//get the video id
videoID = getIntent().getStringExtra("video_id");
youTubePlayerView = findViewById(R.id.youtube_player_view);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
btFullScreen = findViewById(R.id.bt_fullscreen);
btFullScreen.setOnClickListener(view -> {
int orientation = this.getResources().getConfiguration().orientation;
if (null != mPlayer) {
if (mPlayer.isPlaying()) {
mPlayer.pause();
}
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
mPlayer.play();
}
});
mPlayTimeTextView = (TextView) findViewById(R.id.play_time);
mSeekBar = (SeekBar) findViewById(R.id.video_seekbar);
mSeekBar.setOnSeekBarChangeListener(mVideoSeekBarChangeListener);
mHandler = new Handler();
initializeYoutubePlayer();
}
@Override
protected void onResume() {
super.onResume();
if (mPlayer != null) {
initializeYoutubePlayer();
}
}
private void initializeYoutubePlayer() {
youTubePlayerView.initialize(String.valueOf(getText(R.string.youtube_key)), new YouTubePlayer.OnInitializedListener() {
@Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer,
boolean wasRestored) {
if (null == youTubePlayer) return;
mPlayer = youTubePlayer;
displayCurrentTime();
//if initialization success then load the video id to youtube player
if (!wasRestored) {
if (videoID != null) {
youTubePlayer.loadVideo(videoID, seekTime);
}
}
//set the player style here: like CHROMELESS, MINIMAL, DEFAULT
youTubePlayer.setPlayerStyle(YouTubePlayer.PlayerStyle.MINIMAL);
// Add listeners to YouTubePlayer instance
youTubePlayer.setPlayerStateChangeListener(mPlayerStateChangeListener);
youTubePlayer.setPlaybackEventListener(playbackEventListener);
}
private final YouTubePlayer.PlaybackEventListener playbackEventListener = new YouTubePlayer.PlaybackEventListener() {
@Override
public void onPlaying() {
mHandler.postDelayed(runnable, 100);
displayCurrentTime();
}
@Override
public void onPaused() {
mHandler.removeCallbacks(runnable);
}
@Override
public void onStopped() {
mHandler.removeCallbacks(runnable);
}
@Override
public void onBuffering(boolean b) {
}
@Override
public void onSeekTo(int i) {
mHandler.postDelayed(runnable, 100);
}
};
@Override
public void onInitializationFailure(YouTubePlayer.Provider arg0, YouTubeInitializationResult arg1) {
//print or show error if initialization failed
Log.e(TAG, "Youtube Player View initialization failed:" + arg1);
if (arg1.toString().equals("SERVICE_VERSION_UPDATE_REQUIRED")) {
Toast.makeText(YoutubePlayerActivity.this, "Please Update your Youtube to latest version.", Toast.LENGTH_SHORT).show();
}
}
});
}
YouTubePlayer.PlayerStateChangeListener mPlayerStateChangeListener = new YouTubePlayer.PlayerStateChangeListener() {
@Override
public void onLoading() {
}
@Override
public void onLoaded(String s) {
}
@Override
public void onAdStarted() {
}
@Override
public void onVideoStarted() {
displayCurrentTime();
}
@Override
public void onVideoEnded() {
if (null == mPlayer) return;
mPlayer.seekToMillis(0);
mPlayer.pause();
}
@Override
public void onError(YouTubePlayer.ErrorReason errorReason) {
}
};
SeekBar.OnSeekBarChangeListener mVideoSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (null == mPlayer) return;
long lengthPlayed = (mPlayer.getDurationMillis() * seekBar.getProgress()) / 100;
mPlayer.seekToMillis((int) lengthPlayed);
}
};
private void displayCurrentTime() {
//To stop video 1.2s before it ends
if (null == mPlayer) return;
if (mPlayer.getCurrentTimeMillis() >= (mPlayer.getDurationMillis() - 1200L)) {
mPlayer.seekToMillis(0);
mPlayer.pause();
}
String formattedTime = formatTime(mPlayer.getDurationMillis() - mPlayer.getCurrentTimeMillis());
mPlayTimeTextView.setText(formattedTime);
int playPercent = (int) (((float) mPlayer.getCurrentTimeMillis() / (float) mPlayer.getDurationMillis()) * 100);
// update live progress
mSeekBar.setProgress(playPercent);
}
private String formatTime(int millis) {
int seconds = millis / 1000;
int minutes = seconds / 60;
int hours = minutes / 60;
return (hours == 0 ? "" : hours + ":") + String.format("%02d:%02d", minutes % 60, seconds % 60);
}
private Runnable runnable = new Runnable() {
@Override
public void run() {
displayCurrentTime();
mHandler.postDelayed(this, 100);
}
};
@Override
public void onDestroy() {
if (mPlayer != null) {
mPlayer.release();
}
super.onDestroy();
}
@Override
protected void onPause() {
super.onPause();
if (mPlayer != null) {
seekTime = mPlayer.getCurrentTimeMillis();
}
}
@Override
protected void onStop() {
if (mPlayer != null) {
mPlayer.release();
}
super.onStop();
}
// To switch fullScreen icon when orientation changes
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
btFullScreen.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_fullscreen));
} else if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
btFullScreen.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_fullscreen_exit));
}
}
}
我认为直接复制粘贴并添加绘图对象就足以使其正常工作。
如果代码仍然令人困惑,请让我知道,我将向其添加更多注释。
我希望它对每个人都有效!!因为我😅花了一个多小时。
这篇关于在Android中使用YouTube API的最佳方式是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!