Android:即使对象在屏幕上,RecyclerView`getChildAt()`也会返回null

时间:2019-01-16 10:45:40

标签: java android android-recyclerview nullpointerexception recyclerview-layout

我有一个Android活动,其中包含RecyclerView,基本上,我正在创建一个音乐播放器应用。在这里,上一首歌曲按钮应该找到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。除此之外,即使在这个getChildAt()返回空值之后,我也试图阻塞主线程以等待RecyclerView向上滚动(使用无限循环)。

我该如何解决?

P.S。 songIndex是一个类,用于保持当前正在播放的歌曲位置的标签。这是它的代码(以防万一):

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可能会破坏它们),之后,我手动向上滚动,以使当前播放的歌曲位于屏幕的中间(现在它上面有元素),即使现在,当我尝试上一个按钮时,我仍然以某种方式结束了{{1 }}部分:(

1 个答案:

答案 0 :(得分:0)

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