列表视图中的YouTubePlayerSupportFragment项为空。

5
我正试图在列表项中使用YouTubePlayerSupportFragment。这个ListView位于一个Fragment内,而此Fragment又位于一个Activity中。由于存在嵌套的片段,因此我正在使用getChildFragmentManager()方法来查找来自XML布局的片段。以下是代码。

Java

convertView = inflater.inflate(R.layout.youtube_post_layout, null);
YouTubePlayerSupportFragment youTubePlayerFragment = (YouTubePlayerSupportFragment) getChildFragmentManager().findFragmentById(R.id.youtube_video);
if (youTubePlayerFragment == null) {
    Log.i("YouTube", "player is null");
} else {
    Log.i("YouTube", youTubePlayerFragment.toString());
}

XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <include layout="@layout/post_base_layout" />

    <fragment
        android:name="com.google.android.youtube.player.YouTubePlayerSupportFragment"
        android:id="@+id/youtube_video"
        android:layout_width="match_parent"
        android:layout_height="240dp"
        android:layout_marginLeft="62dp"
        android:layout_marginRight="32dp"
        android:background="@color/light_grey"
        android:cropToPadding="true"
        android:padding="1dp"
        android:scaleType="centerCrop" />

    <include layout="@layout/post_bottom_layout" />

</LinearLayout>

问题在于,当我尝试通过执行findFragmentById()从XML中获取该片段时,它返回null,并将其发布到堆栈跟踪中。
我正在尝试遵循YouTube API示例并进行嵌套片段所需的更改,但我找不到导致此问题的原因。

你能分享一下这个命令 adb shell dumpsys activity <activity-name> 的输出吗?它包含了活动和添加的片段列表。 - Manish Mulimani
你使用支持库的碎片吗? - Yuraj
是的,我有支持库片段。 - Douglas Mesquita
1
在ListView中使用片段没有意义,据我所知也无法实际工作。您应该尝试使用YouTubePlayerView替代方案。 - nitzanj
你可以尝试将"getChildFragmentManager"更改为"getSupportChildFragmentManager" - 有时候这样会有所帮助。 - Yuraj
2个回答

3
你所采取的整体方法存在问题。
首先,直接从XML中扩展子片段是不被支持的。在嵌套片段时,必须使用getChildFragmentManager在父片段中动态添加它们。
其次,即使它可以工作(在某些情况下可能会),你已经扩展了视图,但没有将其添加到实际片段的布局中。这就是inflate方法中第二个和第三个参数的用途。FragmentManager将在其当前布局中查找片段,或者在后台堆栈中查找,但无法找到从随机XML扩展并从未被使用的片段。
最后,也是最重要的,您永远不应将片段作为ListView中的项目添加。片段希望具有与它们所在的Activity相关联的生命周期,而ListView或任何一般的AdapterView将根据需要创建、销毁和回收其子项。

可能的解决方案:

  • 你需要在列表中展示多少个视频?如果不是很多,使用ScrollView+LinearLayout可能是最简单的解决方案。

  • 如果你真的需要视图回收,也许你可以考虑在每一行中不使用实时视频?可以考虑在你的行中使用YouTubeThumbnailView,然后将用户重定向到另一个活动/在布局中位于列表之外的单个YoutubeFragment中加载视频。

  • 如果你绝对想要在列表的每一行中直接播放视频,你需要在行布局中使用YoutubePlayerView而不是片段。在这种情况下,请仔细阅读文档,因为你需要自己处理视频初始化和视图回收。


我尝试在ListView中使用YouTubePlayerView,但是每一行的初始化都出现了问题。然后我也尝试了带有YouTubePlayerSupportFragment的ListView,但是当排队播放视频时,它会将位置更改为已加载的视频。它不会在每一行中加载。你能分享任何每行实时视频播放的示例吗? - Anant Shah

1

当您尝试用相同的Fragment填充视图时,您的应用程序将崩溃(例如在quiz中重复使用片段ID)。

有两种解决方案(其中一种来自@ivagarz的答案):

1- 您可以在您的Activity布局中,使用YouTubePlayerViewListView上方显示一个youtube视频,但是您的Activity必须扩展YouTubeBaseActivity,如YouTube Android Player API Doc(我认为这个解决方案不会帮助您解决问题)

2- 您可以使用YouTubeThumbnailViewListView中为每个项目显示youtube视频的缩略图,并在缩略图上使用youtube播放器按钮来播放视频。

就像下面的图片:

enter image description here

"When"用户点击YouTube播放器按钮时,您有两种选择:
第一种选项是使用YouTubePlayerSupportFragment:您可以将YouTubeThumbnailView替换为YouTubePlayerSupportFragment。如果您选择此选项,则必须:
A- 在代码中动态添加YouTubePlayerSupportFragment(以避免在Fragment Id中重复)。
B- 仅在您的ListView中显示一个视频,如这个问题的答案所示。
例如: list_item.xml布局用于ListView项目: "
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/parent_relativeLayout"
   android:layout_width="match_parent"
   android:layout_height="match_parent" >

    <com.google.android.youtube.player.YouTubeThumbnailView
            android:id="@+id/youtube_thumbnail"
            android:layout_width="fill_parent"
            android:layout_height="250dp"
            android:scaleType="centerCrop"
            android:visibility="gone"/>

    <RelativeLayout android:id="@+id/relativeLayout_over_youtube_thumbnail"
        android:layout_width="fill_parent"
        android:layout_height="250dp"
        android:background="@color/color_background_transparent"
        android:visibility="gone">

        <ImageView android:id="@+id/btnYoutube_player"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="center"
            android:src="@drawable/youtube_player"/>

    </RelativeLayout>

</RelativeLayout>

在ListView适配器的getView方法中:
  public View getView(int position, View convertView, ViewGroup parent) {

    convertView = inflator.inflate(R.layout.list_item.xml, parent, false);
    final RelativeLayout relativeLayoutOverYouTubeThumbnailView = (RelativeLayout) convertView.findViewById(R.id.relativeLayout_over_youtube_thumbnail);
    final YouTubeThumbnailView youTubeThumbnailView = (YouTubeThumbnailView) convertView.findViewById(R.id.youtube_thumbnail);

    // get parent relative layout
    RelativeLayout parentRelativeLayout = (RelativeLayout) convertView.findViewById(R.id.parent_relativeLayout);
    // then create dynamic FrameLayout
    FrameLayout.LayoutParams dynamicFrameLayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
    final FrameLayout dynamicFrameLayout = new FrameLayout(ctx);
        dynamicFrameLayout.setId(Different_ID);
        dynamicFrameLayout.setLayoutParams(dynamicFrameLayoutParams);
    // then add dynamic FrameLayout as children in parent relative layout
    parentRelativeLayout.addView(dynamicFrameLayout);

    ImageView youtubePlayerButton = (ImageView) convertView.findViewById(R.id.btnYoutube_player);
    youtubePlayerButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {

            View parentView = (View) v.getParent().getParent();
            YouTubeThumbnailView youTubeThumbnailView = (YouTubeThumbnailView) parentView.findViewById(R.id.youtube_thumbnail);
            RelativeLayout relativeLayoutOverYouTubeThumbnailView = (RelativeLayout) parentView.findViewById(R.id.relativeLayout_over_youtube_thumbnail);
            youTubeThumbnailView.setVisibility(View.GONE);
            relativeLayoutOverYouTubeThumbnailView.setVisibility(View.GONE);
            YouTubeFragment youTubeFragment = new YouTubeFragment();
                youTubeFragment.youTubeFragmentInitialize(VideoID, youTubeFragment, parentView);

            getSupportFragmentManager()
               .beginTransaction()
                    .replace(dynamicFrameLayout.getId(), youTubeFragment)
                    .commit();

        }
    });

    final YouTubeThumbnailLoader.OnThumbnailLoadedListener  onThumbnailLoadedListener = new YouTubeThumbnailLoader.OnThumbnailLoadedListener(){
        @Override
        public void onThumbnailError(YouTubeThumbnailView youTubeThumbnailView, YouTubeThumbnailLoader.ErrorReason errorReason) {

        }

        @Override
        public void onThumbnailLoaded(YouTubeThumbnailView youTubeThumbnailView, String s) {
            loadingImage.setVisibility(View.GONE);
            youTubeThumbnailView.setVisibility(View.VISIBLE);
            relativeLayoutOverYouTubeThumbnailView.setVisibility(View.VISIBLE);
        }
    };

    youTubeThumbnailView.initialize(API_KEY, new YouTubeThumbnailView.OnInitializedListener() {
            @Override
            public void onInitializationSuccess(YouTubeThumbnailView youTubeThumbnailView, YouTubeThumbnailLoader youTubeThumbnailLoader) {

                youTubeThumbnailLoader.setVideo(VideoID);
                youTubeThumbnailLoader.setOnThumbnailLoadedListener(onThumbnailLoadedListener);
            }

            @Override
            public void onInitializationFailure(YouTubeThumbnailView youTubeThumbnailView, YouTubeInitializationResult youTubeInitializationResult) {

            }
        });
}

我创建了一个扩展自YouTubePlayerSupportFragmentFragment
public class YouTubeFragment  extends YouTubePlayerSupportFragment {

    public void youTubeFragmentInitialize(final String videoId, final YouTubeFragment fragment, final View parent) {

        fragment.initialize(apiKey, new YouTubePlayer.OnInitializedListener() {
            @Override
            public void onInitializationSuccess(YouTubePlayer.Provider provider, final YouTubePlayer youTubePlayer, boolean wasRestored) {

           youTubePlayer.setShowFullscreenButton(false);
                if (!wasRestored) {
                    youTubePlayer.loadVideo(videoId);
                }
            }

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

                Log.e("app", youTubeInitializationResult.toString());
            }
        });
    }
}

使用YouTubeStandalonePlayer或创建自己的Activity(扩展YouTubeBaseActivity)是第二种选项:当用户点击YouTube播放器按钮时,您可以创建一个意图来打开新的活动以显示视频。
Intent intent = YouTubeStandalonePlayer.createVideoIntent(context, YOUR_DEVELOPER_KEY, VIDEO_ID);
 startActivity(intent); 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接