简体   繁体   中英

ExoPlayer shows black screen instead of loading video (only sometimes)

I have a recyclerView inside my app witch can load videos and images. I'm using ExoPlayer library to load videos into my recycler view. The problem is that sometimes ExoPlayer show black screen instead of loading the video. I tried to Log the video url from firebase and is not null or something like this.

I'm using this library: https://github.com/HamidrezaAmz/MagicalExoPlayer

Note: This problem appeared when i implemented Pagination (load more post's on scroll) with firebase and recyclerView .

My HomeFragment:

public class HomeFragment extends Fragment {

    LoadingDialog progressDialog;
    final DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
    boolean isSearchOpen = false;
    private EditText searchView;
    ArrayList<PostModel> postModelArrayList;
    ArrayList<PostModel> loadedPostsArrayList;
    RecyclerView recyclerView;
    PostRecyclerAdapter recyclerAdapter;

    int lastLoadedIndex = 0;

    void loadMorePosts() {
        // Load 4 post's per time
        for (int i = 0; i < 3; i++) {
            if (lastLoadedIndex + 1 < postModelArrayList.size()) {
                PostModel postModel = postModelArrayList.get(lastLoadedIndex + 1);
                loadedPostsArrayList.add(postModel);
                recyclerAdapter.notifyDataSetChanged();
                lastLoadedIndex = lastLoadedIndex + 1;
            }
        }
    }

    void loadAllPosts(View fragmentView) {
        DatabaseReference postsRef = FirebaseDatabase.getInstance().getReference("posts");
        postsRef.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {

                new Handler().postDelayed(() -> {
                    fragmentView.findViewById(R.id.constraintLayout2).setVisibility(View.GONE);
                    HomeActivity.bottomNavBar.setVisibility(View.VISIBLE);
                    HomeActivity.showLoadingScreen = false;
                }, 1200);

                for (DataSnapshot postSnapshot : snapshot.getChildren()) {
                    PostModel postModel = postSnapshot.getValue(PostModel.class);

                    // Show post in recycler adapter only if the user is not blocked
                    if (!snapshot.child("users").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("blockedUsers").child(postSnapshot.child("name").getValue(String.class)).exists()) {
                        postModelArrayList.add(postModel);
                    }

                    recyclerAdapter.notifyDataSetChanged();
                }

                // Reverse elements inside postModelArrayList
                Collections.reverse(postModelArrayList);

                // Load first 3 post's
                for (int i = 0; i < 3; i++) {
                    loadedPostsArrayList.add(postModelArrayList.get(i));
                    lastLoadedIndex++;
                }

            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                Toast.makeText(getContext(), "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }

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

        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_home, container, false);

        SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.root_view);
        TextView usernameLoadingScreen = view.findViewById(R.id.textView40);
        ImageButton searchUserBtn = view.findViewById(R.id.searchPersonButton);
        ImageButton notificationsBtn = view.findViewById(R.id.notificationsButton);
        ImageButton searchUserButton = view.findViewById(R.id.enter_search_button);
        View postsOfTheMonthBtn = view.findViewById(R.id.posts_of_the_month_btn);
        searchView = view.findViewById(R.id.search_view);

        recyclerView = view.findViewById(R.id.home_recycler_view);
        loadedPostsArrayList = new ArrayList<>();


        final LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
        recyclerAdapter = new PostRecyclerAdapter(loadedPostsArrayList, getContext(), getActivity());
        
        recyclerView.setAdapter(recyclerAdapter);
        recyclerView.setLayoutManager(layoutManager);

        progressDialog = LoadingDialog.Companion.get(getActivity());

        searchView.setVisibility(View.GONE);
        searchUserButton.setVisibility(View.GONE);

        if (HomeActivity.showWhatsNewMessage) {
            FirebaseInAppMessaging.getInstance().triggerEvent("new_version_open");
        }

        // Avoid data refresh on every swipe down
        recyclerView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) ->
                swipeRefreshLayout.setEnabled(scrollY <= 5));

        // Re-load data
        swipeRefreshLayout.setOnRefreshListener(() -> {
            swipeRefreshLayout.setRefreshing(true);
            loadAllPosts(view);
            swipeRefreshLayout.setRefreshing(false);
        });

        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                loadMorePosts();
            }
        });

        HomeActivity.bottomNavBar.setVisibility(View.GONE);
        loadAllPosts(view);

        return view;
    }

}

My PostRecyclerAdapter:

public class PostRecyclerAdapter extends RecyclerView.Adapter {

    List<PostModel> postList;
    Context context;
    Activity activity;

    @Override
    public int getItemViewType(int position) {
        if (postList.get(position).getPostType().equals("video")) {
            return 1;
        }
        return 0;
    }

    public void addAll(List<PostModel> newPosts) {
        int initSize = postList.size();
        postList.addAll(newPosts);
        notifyItemRangeChanged(initSize, postList.size());
    }

    public String getLastItemID() {
        return postList.get(postList.size() - 1).getId();
    }

    public PostRecyclerAdapter(ArrayList<PostModel> postModelArrayList, Context context, Activity activity) {
        this.postList = postModelArrayList;
        this.context = context;
        this.activity = activity;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (viewType == 1) {
            return new VideoViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.post_video_item, parent, false));
        }
        return new ImageViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.post_item, parent, false));
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {

        DatabaseReference likeRef = FirebaseDatabase.getInstance().getReference("likes");
        FirebaseAuth mAuth = FirebaseAuth.getInstance();
        FirebaseUser user = mAuth.getCurrentUser();

        if (postList.get(position).getPostType().equals("video")) {
            // bind video view holder
            VideoViewHolder videoViewHolder = (VideoViewHolder) holder;
            videoViewHolder.setContext(context);

            // check if post is liked or not
            likeRef.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull @NotNull DataSnapshot snapshot) {
                    if (!HomeActivity.anonymous) {

                        // check if current post is liked from this user
                        if (snapshot.child(videoViewHolder.id).hasChild(user.getUid())) {
                            // post is liked form this user
                            videoViewHolder.like_btn.setImageResource(R.drawable.ic_thumb_up_filled);

                        } else {
                            // post is not liked from this user
                            videoViewHolder.like_btn.setImageResource(R.drawable.ic_thump_up_outline);
                        }
                    } else {
                        // disable like button
                        videoViewHolder.like_btn.setEnabled(false);
                    }

                }

                @Override
                public void onCancelled(@NonNull @NotNull DatabaseError error) {
                    Toast.makeText(context, "error: " + error, Toast.LENGTH_SHORT).show();
                }
            });

            // Get current post id set username, authorID, profile picture URL, postType, likes and post image URL
            videoViewHolder.id = postList.get(position).getId();
            videoViewHolder.username.setText(postList.get(position).getName());
            videoViewHolder.userID = postList.get(position).getAuthorID();
            videoViewHolder.like_counter_tv.setText(postList.get(position).getLikes());
            videoViewHolder.videoURL = postList.get(position).getImgUrl();

            // Load video source
            HashMap<String, String> extraHeaders = new HashMap<>();
            extraHeaders.put("foo", "bar");
            videoViewHolder.andExoPlayerView.setSource(postList.get(position).getImgUrl(), extraHeaders);
            videoViewHolder.andExoPlayerView.setPlayWhenReady(false);
            videoViewHolder.andExoPlayerView.setAspectRatio(EnumAspectRatio.ASPECT_16_9);

            // Load profile picture
            String profilePictureUrl = postList.get(position).getProfileImgUrl();
            if (profilePictureUrl != null) {
                if (!profilePictureUrl.equals("none")) {
                    Glide.with(context).load(profilePictureUrl).into(videoViewHolder.profilePicture);
                }
            }


        } else {

            // bind image view holder
            ImageViewHolder imageViewHolder = (ImageViewHolder) holder;
            imageViewHolder.setContext(context);

            // check if post is liked or not
            likeRef.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull @NotNull DataSnapshot snapshot) {
                    if (!HomeActivity.anonymous) {

                        // check if current post is liked from this user
                        if (snapshot.child(imageViewHolder.postID).hasChild(user.getUid())) {
                            // post is liked form this user
                            imageViewHolder.like_btn.setImageResource(R.drawable.ic_thumb_up_filled);

                        } else {
                            // post is not liked from this user
                            imageViewHolder.like_btn.setImageResource(R.drawable.ic_thump_up_outline);
                        }
                    } else {
                        // disable like button
                        imageViewHolder.like_btn.setEnabled(false);
                    }

                }

                @Override
                public void onCancelled(@NonNull @NotNull DatabaseError error) {
                    Toast.makeText(context, "error: " + error, Toast.LENGTH_SHORT).show();
                }
            });


            // Get current post id set username, authorID, profile picture URL, postType, likes and post image URL
            imageViewHolder.postID = postList.get(position).getId();
            imageViewHolder.username.setText(postList.get(position).getName());
            imageViewHolder.userID = postList.get(position).getAuthorID();
            imageViewHolder.like_counter_tv.setText(postList.get(position).getLikes());

            Picasso.get().load(postList.get(position).getImgUrl()).into(imageViewHolder.postImg);
            imageViewHolder.postImageURL = postList.get(position).getImgUrl();

            // Load profile picture
            String profilePictureUrl = postList.get(position).getProfileImgUrl();
            if (profilePictureUrl != null) {
                if (!profilePictureUrl.equals("none")) {
                    Glide.with(context).load(profilePictureUrl).into(imageViewHolder.profileImage);
                }
            }
        }

    }


    @Override
    public int getItemCount() {
        return postList.size();
    }

}

My video_post_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/video_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_margin="12dp"
    app:cardElevation="8dp"
    app:cardCornerRadius="10dp">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/sContainer"
        android:layout_width="match_parent"
        android:background="?attr/cardBackgroundColor"
        android:layout_height="wrap_content">

        <de.hdodenhof.circleimageview.CircleImageView
            android:id="@+id/circleImageView2"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:src="@drawable/user"
            app:layout_constraintEnd_toStartOf="@+id/textView27"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/textView27"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:text="username"
            android:textColor="?attr/titleTextColor"
            android:textSize="17sp"
            android:textStyle="bold"
            app:layout_constraintBottom_toBottomOf="@+id/circleImageView2"
            app:layout_constraintStart_toEndOf="@+id/circleImageView2"
            app:layout_constraintTop_toTopOf="@+id/circleImageView2" />

        <com.potyvideo.library.AndExoPlayerView
            android:id="@+id/andExoPlayerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            app:andexo_show_full_screen="true"
            app:keep_content_on_player_reset="true"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView27"
            app:layout_constraintVertical_bias="1.0" />

        <ImageButton
            android:id="@+id/imageButton8"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="15dp"
            android:background="@null"
            app:layout_constraintBottom_toBottomOf="@+id/textView27"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="@+id/textView27"
            app:srcCompat="@drawable/ic_thumb_up" />

        <TextView
            android:id="@+id/textView36"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="8dp"
            android:text="0"
            android:textColor="?attr/titleTextColor"
            android:textSize="18sp"
            android:textStyle="bold"
            app:layout_constraintBottom_toBottomOf="@+id/imageButton8"
            app:layout_constraintEnd_toStartOf="@+id/imageButton8"
            app:layout_constraintTop_toTopOf="@+id/imageButton8" />

        <View
            android:id="@+id/view5"
            android:layout_width="200dp"
            android:layout_height="55dp"
            android:focusable="true"
            android:foreground="?selectableItemBackgroundBorderless"
            app:layout_constraintBottom_toTopOf="@+id/andExoPlayerView"
            app:layout_constraintEnd_toEndOf="@+id/textView27"
            app:layout_constraintStart_toStartOf="@+id/circleImageView2"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>

Move the addview method from onScrollStateChanged to onPlayerStateChanged method of exoplayer. By adding view in onscrollstatechanged it was trying to add the view at every fraction of a second.

Also, Add a handler, which keeps checking the state of a variable if the view is not added then add the view, this way, the view gets added most of the time either via onPlayerStateChanged method or by the handler. It resolves in most of the cases but still not 100%.

Here I'm adding a reference to the issue https://github.com/google/ExoPlayer/issues/7750

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM