首页 > 解决方案 > Android:即使对象在屏幕上,RecyclerView `getChildAt()` 也会返回 null

问题描述

我有一个包含 RecyclerView 的 Android 活动,基本上,我正在创建一个音乐播放器应用程序。在这里,上一首歌曲按钮应该是找到RecyclerView的前一个元素并点击它(这将播放歌曲),这样做,当我使用时recyclerView.getChildAt(),它返回null,导致错误。

这是onClickListener“上一个”按钮的代码...

prevSong_bottomSheet.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // We start by checking if this is the first song or not!
            if (songIndex.getCurrentIndex() == 0) {
                Toast.makeText(MainActivity.this, "Nothing to play before this", Toast.LENGTH_SHORT).show();

                // Now, this simply return as we don't want to execute any of the following code!
                return;
            }

            Log.d(DEBUG_MESSAGE, "Original song index: " + songIndex.getCurrentIndex());

            try {
                // First, as we know that we'll be playing the previous audio, we start by decrementing
                //  the value inside `SongIndex`.
                songIndex.prevSongPlayed();

                // As the value inside `SongIndex` has been decremented, we use the same here!
                View parentView = recyclerView.getChildAt(songIndex.getCurrentIndex());
                // Now we extract the action button associated with this particular view!
                Button tempButton = parentView.findViewById(R.id.music_actionButton);

                // Now that we've got the button, instead of calling `startSong()` directly, we'll
                //  perform a click on the button, this way if we decide to perform some other action (in the future)
                //  once the user clicks that button, the action would still be valid!
                tempButton.performClick();
                Log.d(DEBUG_MESSAGE, "Previous song played successfully!");
            } catch (NullPointerException e) {
                // Lastly, if any error occurred in the above code, in the first line itself, we
                //  have already decremented SongIndex in the first line itself, thus, we increment
                //  it here to balance it out!
                //songIndex.nextSongPlayed();
                Log.d(DEBUG_MESSAGE, e.getLocalizedMessage() + "\n\n\n\n\n\n");
                e.printStackTrace();

                Log.d(DEBUG_MESSAGE, "Final song index: " + songIndex.getCurrentIndex());

            }
        }
    });

运行上面的代码时,只要 RecyclerView 的下一个元素在屏幕上,它就可以正常运行,但是当视图离开屏幕时开始返回 null!

是的,我知道 RecyclerView 会破坏屏幕外的元素(甚至不创建它们)。为了解决这个问题,我尝试使用recyclerView.scrollToPosition(),即使这样做了,它也会返回 null。我试图向上滚动到前一个元素的位置,甚至在它上方 2 或 3 个位置,仍然getChildAt()返回 null。除此之外,我还尝试阻止主线程等待 RecyclerView 向上滚动(使用无限循环),即使在getChildAt()返回 null 之后也是如此。

我该如何解决这个问题?

PSsongIndex是一个类,它应该在当前播放的歌曲的位置上保持标签。这是它的代码(以防万一):

private class SongIndex {
    /**
     * This class is used to keep a track as to which song is being played currently, the data member
     * created inside this class would be regularly updated using the functions defined below!
     * Thus, this class will be used at various instances inside the program to know about the
     * index of the song (inside the RecyclerView) which is being played currently!
     */

    private int currentSongIndex;

    public int getCurrentIndex() {
        return currentSongIndex;
    }

    public void setCurrentSongIndex(int currentSongIndex) {
        this.currentSongIndex = currentSongIndex;
    }

    public void nextSongPlayed() {
        currentSongIndex++;
    }

    public void prevSongPlayed() {
        currentSongIndex--;
    }
}

PSS 我试图解决的另一件事是,当我到达屏幕顶部时(上面会有更多元素,但它们都不会出现在屏幕上,即 RecyclerView 可能会破坏它们),在那之后,我手动向上滚动,以便当前播放的歌曲位于屏幕中间(现在它上面有元素),即使是现在,当我尝试上一个按钮时,我仍然以某种方式结束了catch部分:(

标签: javaandroidandroid-recyclerviewnullpointerexceptionrecyclerview-layout

解决方案


根据您共享的代码, currentSongIndex 未初始化。它将有一些垃圾值,因此您的 if 条件 (songIndex.getCurrentIndex() == 0) 第一次将为 false,而 songIndex.getCurrentIndex() 将返回垃圾,因此 recyclerView.getChildAt(songIndex.getCurrentIndex()); 将为空


推荐阅读