Android Studio报错:Attempt to get length of null array问题求助
Android音乐应用RecyclerView条目点击崩溃问题修复
问题现象
点击RecyclerView中的音乐条目时应用崩溃,Logcat报错:Attempt to get length of null array,确认主列表不为空,怀疑Intent传递环节出错。
核心错误原因
- Intent传递缺失关键数据:MusicAdapter跳转至SongPlayerActivity时,仅传递了
song_name,但SongPlayerActivity尝试获取未传递的musicList和songIndex,导致songList为null,调用songList.get(currentSongIndex)触发空指针异常,对应Logcat中的"null array"错误。 - 数据存储类型不匹配: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(); } } // ... 暂停、切歌、播放完成回调、销毁逻辑不变 }
额外优化点
- 在SongPlayerActivity中增加
songList的空判断,避免因数据传递异常导致崩溃 - MainActivity中关闭Cursor前增加空判断,防止Cursor为null时调用close()引发异常
内容的提问来源于stack exchange,提问作者ReventoN671
相关产品推荐
相关产品推荐

