android - 如何在 Android 的 ViewPager 中的 fragment 中播放 Youtube 视频

标签 android video youtube android-viewpager fragment

现在我正在尝试使用 YouTubePlayerSupportFragment 在 ViewPager 的 fragment 中播放 Youtube 视频。
我使用 SmartFragmentStatePagerAdapter 作为 viewpager 适配器。
但我收到了这个错误:

W/YouTubeAndroidPlayerAPI:由于播放器顶部未经授权的覆盖,YouTube 视频播放停止。 YouTubePlayerView 不包含在其祖先 android.support.v4.view.ViewPager{41a53898 VFED.... ......I. 0,84-480,730 #7f0c00b8 app:id/viewPager}。祖先的边缘与 YouTubePlayerView 的边缘之间的距离是:左:480,上:0,右:-480,下:376(这些都应该是正数)。

我该如何解决这个问题。
问候

这是 FragmentPageAdapter 代码

public class VideoPagerAdapter extends SmartFragmentStatePagerAdapter 

{
    private UserInfo usrInfo;

public VideoPagerAdapter(FragmentManager fragmentManager, UserInfo userInfo){
    super(fragmentManager);
    usrInfo = userInfo;
}

@Override
public Fragment getItem(int position) {
    VideoDetailFragment videoDetailFragment = new VideoDetailFragment();
    videoDetailFragment.video = usrInfo.videoList.get(position);
    return videoDetailFragment;
}

@Override
public int getCount() {
    return usrInfo.videoList.size();
}

}

我已经在 VideoDetailFragment 中实现了代码。
private YouTubePlayer mYoutubePlayer;
private YouTubePlayerSupportFragment mYoutubeFragment;

private void initYoutubeVideo(){
    mYoutubeFragment = YouTubePlayerSupportFragment.newInstance();
    FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
    transaction.replace(R.id.youtube_layout, mYoutubeFragment).commit();

    mYoutubeFragment.initialize(DEVELOPER_KEY, this);
}

@Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {
    mYoutubePlayer = youTubePlayer;
    if (!b){
        youTubePlayer.setPlayerStyle(YouTubePlayer.PlayerStyle.DEFAULT);
        youTubePlayer.loadVideo(VIDEO_ID);
    }
}



@Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
    Log.d(TAG, "*** Youtube Player error : " + youTubeInitializationResult.toString());
    String errorMessage = String.format(getString(R.string.error_youtube_player), youTubeInitializationResult.toString());

    Utils.showAlert(mActivity, errorMessage);
}

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

    if (!isVisibleToUser && mYoutubePlayer != null) {
        mYoutubePlayer.release();
    }
    if (isVisibleToUser && mYoutubeFragment != null) {
        mYoutubeFragment.initialize(DEVELOPER_KEY, this);
    }
}

我已经在真实设备上测试过了
06-08 19:02:47.012 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: Cannot load modern controls UI. Upgrade to the latest version of the Android YouTube API.
06-08 19:02:47.082 2562-2562/com.videofeed.tickit D/dalvikvm: DexOpt: couldn't find field Landroid/view/accessibility/CaptioningManager$CaptionStyle;.windowColor
06-08 19:02:47.082 2562-2562/com.videofeed.tickit W/dalvikvm: VFY: unable to resolve instance field 10579
06-08 19:02:47.082 2562-2562/com.videofeed.tickit D/dalvikvm: VFY: replacing opcode 0x52 at 0x0019
06-08 19:02:47.082 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: Forcefully created overlay:vtd@41fd4d28 helper:Lazy@41fd5898 view:null status: ...... {...}
06-08 19:02:47.372 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: Cannot load modern controls UI. Upgrade to the latest version of the Android YouTube API.
06-08 19:02:47.442 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: Forcefully created overlay:vtd@42c9fe20 helper:Lazy@42c9fe98 view:null status: ...... {...}
06-08 19:02:47.462 2562-2562/com.videofeed.tickit I/Choreographer: Skipped 40 frames!  The application may be doing too much work on its main thread.
06-08 19:02:47.602 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: Cannot load modern controls UI. Upgrade to the latest version of the Android YouTube API.
06-08 19:02:47.692 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: Forcefully created overlay:vtd@42d8f2a8 helper:Lazy@42d8f320 view:null status: ...... {...}
06-08 19:02:51.912 2562-2604/com.videofeed.tickit D/dalvikvm: GC_FOR_ALLOC freed 15971K, 69% free 7899K/25052K, paused 35ms, total 37ms
06-08 19:02:58.202 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: YouTube video playback stopped due to unauthorized overlay on top of player. The YouTubePlayerView is not contained inside its ancestor android.support.v4.view.ViewPager{42c4a610 VFED.... ......ID 0,84-480,730 #7f0c00b8 app:id/viewPager}. The distances between the ancestor's edges and that of the YouTubePlayerView is: left: -480, top: 0, right: 480, bottom: 376 (these should all be positive).
06-08 19:02:58.222 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: YouTube video playback stopped due to unauthorized overlay on top of player. The YouTubePlayerView is not contained inside its ancestor android.support.v4.view.ViewPager{42c4a610 VFED.... ......ID 0,84-480,730 #7f0c00b8 app:id/viewPager}. The distances between the ancestor's edges and that of the YouTubePlayerView is: left: 480, top: 0, right: -480, bottom: 376 (these should all be positive).

这是登录 Android 工作室。
我附上了截图。
This is the screenshot

最佳答案

这个答案可能为时已晚,但我找到了一个可能的解决方案。

我遇到了类似的问题,我也尝试在 viewpager 中播放多个视频。
如果 viewpager 中只有一个 youtube fragment ,没关系,但是当有多个 fragment 时,视频将无法播放,并显示该错误消息

YouTube video playback stopped due to unauthorized overlay on top of player.



第一个“未经授权的覆盖”不是来自我当前的 fragment ,它位于
查看寻呼机的可见页面。它来自查看寻呼机创建的页面 “下一个” 到当前 fragment 。

查看寻呼机在滑入可见窗口之前创建页面,因此 youtube fragment 是在可见之前创建的,如果您 初始化 该 fragment ,然后 youtube 播放器检测到奇怪的覆盖错误并停止视频,然后 youtube 播放器停止,甚至停止在可见页面中正常显示的视频。

在您的情况下,您可以看到错误消息

left: 480, top: 0, right: -480, bottom: 376



负数是一个窗口宽,所以它的概率与我得到的问题相同。

所以我的解决方案

1. 不要在 onCreate() 初始化 youtube,不要在该 fragment 对 viewpager 可见之前进行初始化。

就我而言,我使用适配器和 fragment 之间的接口(interface),并在 viewpager 的父页面中,将 OnPageChangeListener 添加到 viewpager,youtube fragment 仅在 viewpager 的页面更改为该 youtube fragment 后初始化。

页面更改 > 通知适配器 > 界面 > youtubefragment > 开始初始化

第一步后,即使 viewpager 中有 2 个或更多 youtube fragment ,第一个视频也应该正常播放,但是当我滑动到第 2 页时,视频不会播放并显示相同的错误,所以转到第 2 步

2.当youtube fragment 滑动到 View 寻呼机的不可见部分时释放youtube播放器

第二个视频不播放的原因是一样的,第一页有一个 youtubeplayer,它在可见范围之外,它收到一条错误消息,停止所有 youtubeplayer,原因我不知道为什么。

当页面更改时,我使用相同的界面。适配器会通过该接口(interface)通知正在滑开的 youtube fragment ,释放 youtubeplayer,该接口(interface)就是这样实现的,其中 mPlayer 就是 youtubeplayer 通过 initialize 方法返回的。
      mInitializeListener = new InitializeListener() {
        @Override
        public void startVideo() {
            initialize();
        }

        @Override
        public void stopVideo() {
                mPlayer.release();
        }
    };

还有一些问题我无法回答
就像为什么一个寻呼机中的 youtubeplayer 会影响其他人..?

但是当我对我的适配器和 fragment 进行更改时,
youtube视频可以正常播放,希望对你有帮助

以下是我在我的应用程序中使用的代码
    MediaFragmentViewPager adapter =
        new MediaFragmentViewPager(getChildFragmentManager(), getActivity(), true);
List<MediaData> mediaDataList = new ArrayList<>();

adapter.setmResources(mediaDataList);

imageViewPager.setAdapter(adapter);

ViewPager.OnPageChangeListener pagerchangeListener = new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }
    @Override
    public void onPageSelected(int position) {
        adapter.onPageChanged(position);
    }
    @Override
    public void onPageScrollStateChanged(int state) {

    }
};

imageViewPager.addOnPageChangeListener(pagerchangeListener);
pagerchangeListener.onPageSelected(0);

circlePageIndicator.setFillColor(getResources().getColor(R.color.colorAccent));
circlePageIndicator.setViewPager(imageViewPager);

适配器
public class MediaFragmentViewPager  extends FragmentStatePagerAdapter
        implements MediaYoutubeFragment.MediaFullScreenListener {

    protected List<MediaData> mResources;
    private String apiKey = "your apiKey";
    protected Map<Integer, MediaYoutubeFragment.InitializeListener> listenerMap = new HashMap<>();
    private Context context;

    private boolean isFullScreen;

    public MediaFragmentViewPager(FragmentManager fm, Context context, boolean isFullScreen) {
        super(fm);
        this.context = context;
        this.isFullScreen = isFullScreen;
    }

    public int currentPosition = -1;


    @Override
    public void startFullScreen() {
        if (!isFullScreen){
            MediaViewPagerActivity.startActivity(context, itemID, companyId, currentPosition);
        }
    }

    @Override
    public Fragment getItem(int position) {

        if(mResources.get(position).isImage == true){
            Log.i("tag3", "getItem image" + String.valueOf(position));
            MediaImageFragment imageFragment = new MediaImageFragment();
            imageFragment.setImageUrl(mResources.get(position).getImageResource().getImage1080p());
            return  imageFragment;
        } else {
            Log.i("tag3", "getItem video" + String.valueOf(position));
            MediaYoutubeFragment youTubePlayerSupportFragment =
                    MediaYoutubeFragment.newInstance(mResources.get(position).getYoutubeUrl(), this);
            listenerMap.put(position, youTubePlayerSupportFragment.getmInitializeListener());
            return youTubePlayerSupportFragment;
        }
    }

    public void onPageChanged(int position){
        // current page it not null, realse youtubeplayer.
        if(currentPosition != -1){
            if(listenerMap.get(currentPosition) != null){
                listenerMap.get(currentPosition).stopVideo();
            }
        }
        // update current position
        currentPosition = position;
        Log.i("tag3", "onPageSelected " + String.valueOf(position));

        //start loading video
        MediaYoutubeFragment.InitializeListener listener = listenerMap.get(position);
        if(listener != null){
            Log.i("tag3", "startVideo " + String.valueOf(position));
            listener.startVideo();
        } else {
            Log.i("tag3", "startVideo listener is null " + String.valueOf(position));
        }
    }

    @Override
    public int getCount() {
        return mResources.size();
    }

    public List<MediaData> getmResources() {
        return mResources;
    }

    public void setmResources(List<MediaData> mResources) {
        this.mResources = mResources;
    }


}

Youtube fragment
public class MediaYoutubeFragment extends YouTubePlayerSupportFragment
        implements YouTubePlayer.OnInitializedListener, YouTubePlayer.OnFullscreenListener {
    private static final String KEY_VIDEO_ID = "VIDEO_ID";

    public String apiKey = "yor apiKey";
    private String mVideoId;
    private YouTubePlayer mPlayer;
    boolean mIsFullScreen;
    private InitializeListener mInitializeListener;
    private MediaFullScreenListener fullScreenListener;

    public InitializeListener getmInitializeListener() {
        return mInitializeListener;
    }

    public void setmInitializeListener(InitializeListener mInitializeListener) {
        this.mInitializeListener = mInitializeListener;
    }

    public void setFullScreenListener(MediaFullScreenListener fullScreenListener) {
        this.fullScreenListener = fullScreenListener;
    }

    public interface MediaFullScreenListener{
        void startFullScreen();
    }

    public interface InitializeListener{
        void startVideo();
        void stopVideo();
    }

    public MediaYoutubeFragment(){
        super();
        mInitializeListener = new InitializeListener() {
            @Override
            public void startVideo() {
                initialize();
            }

            @Override
            public void stopVideo() {
                if (mPlayer != null){
                    mPlayer.release();
                }
            }
        };
    }

    private void initialize() {
        initialize(apiKey, this);
    }

    public static MediaYoutubeFragment newInstance(String videoId, MediaFullScreenListener listener) {
        MediaYoutubeFragment frag = new MediaYoutubeFragment();

        Bundle args = new Bundle();
        args.putString(KEY_VIDEO_ID, videoId);

        frag.setArguments(args);
        frag.setFullScreenListener(listener);
        return frag;
    }

    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);

        if (getArguments() != null) {
            mVideoId = getArguments().getString(KEY_VIDEO_ID);
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
     }

    @Override
    public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean wasRestored) {
        mPlayer = youTubePlayer;

        mPlayer.setFullscreenControlFlags(FULLSCREEN_FLAG_CUSTOM_LAYOUT);
        mPlayer.setOnFullscreenListener(this);
        mPlayer.setFullscreen(false);
        mPlayer.setShowFullscreenButton(true);

        if (!wasRestored) {
            // load your video
            mPlayer.loadVideo(mVideoId);
        }
        else
        {
            mPlayer.play();
        }
    }

    @Override
    public void onInitializationFailure(YouTubePlayer.Provider provider,
                                        YouTubeInitializationResult youTubeInitializationResult) {

    }

    @Override
    public void onFullscreen(boolean fullscreen) {
        Log.i("tag3", "onFullscreen" + String.valueOf(fullscreen));
        mPlayer.setFullscreen(false);
        fullScreenListener.startFullScreen();
    }

}

我也用自己的 Activity 处理全屏事件,这个viewpager内容不仅是youtube视频,还有图片,所以请忽略那些部分。

因为我在 fragment 中使用了 View 寻呼机,所以我使用了getChildFragmentManger,我也在Activity中使用了这个适配器,但是它产生了另一个问题,第一个视频不会在第一次viewpager isload时播放,因为监听器是在getItem( ) 在适配器中,所以我做了一些更改,如果适配器是第一次加载(第一个 youtube 页面是第一次加载),监听器将在 getItem 返回 fragment 后立即调用,其他的都是一样的。

关于android - 如何在 Android 的 ViewPager 中的 fragment 中播放 Youtube 视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44427611/

相关文章:

android - 如何在android设备上读取beacon的UDID、Major、Minor?

android - libgdx 游戏非常高 "Maximum memory use"

video - ffmpeg中带有png图像的电影

c# - Directshow录制/预览问题

python - 从YouTube获取标题

android - 在 Android 中读取大型列表以获取 AutoCompleteTextView

android - 如何使用 MS Visual Studio 进行 Android 开发?

video - 修复 iframe 853 by 480 中的 YouTube 黑色侧边栏

php - youtube iframe API 中的 playVideoAt() 函数不起作用

api - YouTube API 返回特定类别中所有视频的列表