You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio报错:Attempt to get length of null array问题求助

Android音乐应用RecyclerView条目点击崩溃问题修复

问题现象

点击RecyclerView中的音乐条目时应用崩溃,Logcat报错:Attempt to get length of null array,确认主列表不为空,怀疑Intent传递环节出错。

核心错误原因

  1. Intent传递缺失关键数据:MusicAdapter跳转至SongPlayerActivity时,仅传递了song_name,但SongPlayerActivity尝试获取未传递的musicList和songIndex,导致songList为null,调用songList.get(currentSongIndex)触发空指针异常,对应Logcat中的"null array"错误。
  2. 数据存储类型不匹配:MainActivity的musicList仅存储歌曲标题,而SongPlayerActivity需要歌曲文件路径才能播放,现有数据无法满足播放需求。

修复步骤及代码修改

1. 修改MainActivity,存储完整Song对象

将存储标题的ArrayList<String>改为存储Song对象,获取媒体库中的歌曲路径、标题等信息:

public class MainActivity extends AppCompatActivity {
    private static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 0;
    RecyclerView recyclerView;
    MusicAdapter musicAdapter;
    ArrayList<Song> musicList; // 修改类型为Song列表
    SharedPreferences sharedPreferences;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.RecyclerView);
        musicList = new ArrayList<Song>(); // 初始化Song列表
        sharedPreferences = getSharedPreferences("removed_songs", MODE_PRIVATE);
        musicAdapter = new MusicAdapter(musicList, this, sharedPreferences); // 传递Song列表

        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(musicAdapter);

        // ... 权限申请、刷新按钮逻辑不变
    }

    private void getMusic() {
        musicList.clear();
        ContentResolver contentResolver = getContentResolver();
        Uri songUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
        Cursor songCursor = contentResolver.query(songUri, null, selection, null, null);
        if (songCursor != null && songCursor.moveToFirst()) {
            int songTitle = songCursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
            int songPath = songCursor.getColumnIndex(MediaStore.Audio.Media.DATA); // 获取歌曲路径
            int songDuration = songCursor.getColumnIndex(MediaStore.Audio.Media.DURATION); // 获取时长
            do {
                String currentTitle = songCursor.getString(songTitle);
                String currentPath = songCursor.getString(songPath);
                String currentDuration = songCursor.getString(songDuration);
                String removedSong = sharedPreferences.getString(currentTitle, null);
                if (removedSong == null) {
                    musicList.add(new Song(currentPath, currentTitle, currentDuration)); // 添加完整Song对象
                }
            } while (songCursor.moveToNext());
        }
        if(songCursor != null) songCursor.close(); // 增加空判断避免NPE
        musicAdapter.notifyDataSetChanged();
    }

    // ... 权限回调逻辑不变
}

2. 修改MusicAdapter,传递正确的Intent数据

适配Song对象列表,并在跳转时传递完整歌曲列表和当前索引:

public class MusicAdapter extends RecyclerView.Adapter<MusicAdapter.MusicViewHolder> {
    private List<Song> musicList; // 修改为Song列表
    private Context context;
    private SharedPreferences sharedPreferences;

    // 构造方法接收Song列表
    public MusicAdapter(ArrayList<Song> musicList, Context context, SharedPreferences sharedPreferences) {
        this.musicList = musicList;
        this.context = context;
        this.sharedPreferences = sharedPreferences;
    }

    @NonNull
    @Override
    public MusicViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.music_item, parent, false);
        return new MusicViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MusicViewHolder holder, @SuppressLint("RecyclerView") int position) {
        final Song song = musicList.get(position); // 获取Song对象
        holder.songNameTextView.setText(song.getTitle()); // 显示标题

        // 删除按钮逻辑适配Song对象
        holder.removeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                AlertDialog.Builder builder = new AlertDialog.Builder(context);
                builder.setTitle("确定要从列表中移除这首歌吗?");
                builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        musicList.remove(song);
                        SharedPreferences.Editor editor = sharedPreferences.edit();
                        editor.putString(song.getTitle(), song.getTitle());
                        editor.apply();
                        notifyDataSetChanged();
                    }
                });
                builder.setNegativeButton("否", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                });
                builder.show();
            }
        });

        // 条目点击跳转,传递完整列表和索引
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(context, SongPlayerActivity.class);
                intent.putExtra("musicList", musicList); // 传递Song列表(Song已实现Serializable)
                intent.putExtra("songIndex", position); // 传递当前点击索引
                context.startActivity(intent);
            }
        });
    }

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

    // ... ViewHolder逻辑不变
}

3. 修改SongPlayerActivity,接收并使用正确数据

适配Song对象列表,通过Song的路径播放音乐:

public class SongPlayerActivity extends AppCompatActivity implements MediaPlayer.OnCompletionListener {

    private MediaPlayer mediaPlayer;
    private ArrayList<Song> songList; // 修改为Song列表
    private int currentSongIndex;
    private boolean isPlaying = false;
    private ImageButton playBtn, nextBtn, prevBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.song_player);

        Intent intent = getIntent();
        songList = (ArrayList<Song>) intent.getSerializableExtra("musicList"); // 获取Song列表
        currentSongIndex = intent.getIntExtra("songIndex", 0);

        // 空判断避免崩溃
        if(songList == null || songList.isEmpty()){
            Toast.makeText(this, "无可用歌曲", Toast.LENGTH_SHORT).show();
            finish();
            return;
        }

        // 初始化MediaPlayer
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setOnCompletionListener(this);

        // 初始化UI元素
        playBtn = findViewById(R.id.pause_play);
        nextBtn = findViewById(R.id.next);
        prevBtn = findViewById(R.id.previous);

        // ... 播放控制按钮逻辑不变

        // 播放当前歌曲
        playSong();
    }

    private void playSong() {
        try {
            mediaPlayer.reset();
            Song currentSong = songList.get(currentSongIndex);
            mediaPlayer.setDataSource(currentSong.getPath()); // 使用Song对象的路径
            mediaPlayer.prepare();
            mediaPlayer.start();
            isPlaying = true;
            playBtn.setImageResource(R.drawable.pause);
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(this, "播放失败", Toast.LENGTH_SHORT).show();
        }
    }

    // ... 暂停、切歌、播放完成回调、销毁逻辑不变
}

额外优化点

  1. 在SongPlayerActivity中增加songList的空判断,避免因数据传递异常导致崩溃
  2. MainActivity中关闭Cursor前增加空判断,防止Cursor为null时调用close()引发异常

内容的提问来源于stack exchange,提问作者ReventoN671

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:27:05