ViewPager2中音频与图文加载顺序不匹配问题求助
解决ViewPager2滑动切歌时音频与图文顺序不匹配问题
问题根源
当前MusicAdapter中的MediaPlayer是全局成员变量,而ViewPager2会预加载相邻页面,同时ViewHolder存在复用机制。当多个页面绑定数据时,全局的mediaPlayer会被不断覆盖,导致滑动时音频实例与当前页面不对应,出现顺序错乱。而图文直接绑定到ViewHolder的控件,不受全局变量影响,因此保持正确顺序。
修改方案
1. 将MediaPlayer移至ViewHolder内部
让每个ViewHolder持有独立的MediaPlayer实例,确保每个页面的音频逻辑相互隔离:
修改后的MusicAdapter.java:
public class MusicAdapter extends RecyclerView.Adapter<MusicAdapter.MusicViewHolder> { private final Context context; private final List<AllMusicModel.Data> mMusiclist; public MusicAdapter(Context context, List<AllMusicModel.Data> musicItems) { this.context = context; mMusiclist = musicItems; } @NonNull @Override public MusicViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new MusicViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.music_layout, parent, false)); } @Override public void onBindViewHolder(@NonNull MusicViewHolder holder, int position) { holder.setMusicData(mMusiclist.get(position)); } @Override public int getItemCount() { return mMusiclist.size(); } class MusicViewHolder extends RecyclerView.ViewHolder { ImageView mImageView, play_pause_image; TextView txtTitle, txtDesc; ProgressBar mProgressBar; ConstraintLayout play_pause_layout, linearLayout; private MediaPlayer mediaPlayer; private Handler handler = new Handler(); public MusicViewHolder(@NonNull View itemView) { super(itemView); mImageView = itemView.findViewById(R.id.imageView); txtTitle = itemView.findViewById(R.id.txtTitle); txtDesc = itemView.findViewById(R.id.txtDesc); mProgressBar = itemView.findViewById(R.id.progressBar); play_pause_layout = itemView.findViewById(R.id.play_pause_layout); play_pause_image = itemView.findViewById(R.id.play_pause_image); linearLayout = itemView.findViewById(R.id.linearLayout); } void setMusicData(AllMusicModel.Data musicItem) { txtTitle.setText(musicItem.getTitle()); // 重置当前ViewHolder的MediaPlayer if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } play_pause_image.setImageResource(R.drawable.ic_round_pause); play_pause_layout.setVisibility(View.INVISIBLE); mImageView.setOnClickListener(v -> { if (mediaPlayer != null) { if (mediaPlayer.isPlaying()) { mediaPlayer.pause(); play_pause_image.setImageResource(R.drawable.ic_round_play); play_pause_layout.setVisibility(View.VISIBLE); } else { mediaPlayer.start(); play_pause_image.setImageResource(R.drawable.ic_round_pause); play_pause_layout.setVisibility(View.VISIBLE); handler.removeCallbacksAndMessages(null); handler.postDelayed(() -> play_pause_layout.setVisibility(View.INVISIBLE), 4000); } } }); String audioUrl = ApiUrls.Api_LocalHost_Url + musicItem.getAudio(); mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); try { mediaPlayer.setDataSource(audioUrl); mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(mp -> { mProgressBar.setVisibility(View.GONE); mp.start(); }); } catch (IOException e) { e.printStackTrace(); mProgressBar.setVisibility(View.GONE); } mediaPlayer.setOnCompletionListener(mp -> mp.start()); String imageUrl = ApiUrls.Api_LocalHost_Url + musicItem.getImage(); Glide.with(context) .load(imageUrl) .placeholder(R.drawable.loading) .diskCacheStrategy(DiskCacheStrategy.ALL) .error(R.drawable.loading) .into(mImageView); } // 供外部调用的停止音频方法 public void stopAudio() { if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.stop(); } handler.removeCallbacksAndMessages(null); } // 释放资源,避免内存泄漏 @Override protected void finalize() throws Throwable { super.finalize(); if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } } } }
2. 监听ViewPager2页面切换,停止前一页音频
在MusicFragment中添加页面切换监听,确保切换页面时停止上一页的音频播放:
修改后的MusicFragment.java:
public class MusicFragment extends Fragment { View v; List<AllMusicModel.Data> musicItems; ViewPager2 musicsViewPager; private MusicAdapter musicAdapter; private int currentPosition = 0; @RequiresApi(api = Build.VERSION_CODES.M) @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { v = inflater.inflate(R.layout.fragment_music, container, false); musicsViewPager = v.findViewById(R.id.viewPagerVideos); musicsViewPager.setUserInputEnabled(true); musicItems = new ArrayList<>(); musicAdapter = new MusicAdapter(getActivity(), musicItems); musicsViewPager.setAdapter(musicAdapter); // 页面切换监听 musicsViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { super.onPageSelected(position); if (currentPosition != position) { RecyclerView recyclerView = (RecyclerView) musicsViewPager.getChildAt(0); MusicAdapter.MusicViewHolder prevHolder = (MusicAdapter.MusicViewHolder) recyclerView.findViewHolderForAdapterPosition(currentPosition); if (prevHolder != null) { prevHolder.stopAudio(); } currentPosition = position; } } }); call_music_list_api(); return v; } // 原有API调用方法保持不变 private void call_music_list_api() { String Token = "Bearer " + Config.getToken(requireContext()); String APIChannel = "App"; String AppVersion = BuildConfig.VERSION_NAME; Call<AllMusicModel> mCall = RetrofitClient.getAdapter().GetAllMusic(APIChannel, AppVersion, Token); mCall.enqueue(new Callback<AllMusicModel>() { @SuppressLint("NotifyDataSetChanged") @Override public void onResponse(@NonNull Call<AllMusicModel> call, @NonNull Response<AllMusicModel> response) { if (response.isSuccessful()) { AllMusicModel alldata = response.body(); if (alldata != null) { String code = String.valueOf(alldata.getStatuscode()); if (code.equals("200")) { musicItems.clear(); musicItems.addAll(alldata.getData()); musicAdapter.notifyDataSetChanged(); } else if (Objects.equals(code, "401")) { Log.e("MusicFragment", "onResponse: " + alldata.getStatus()); } } } else { Toast.makeText(getContext(), "Something went wrong", Toast.LENGTH_SHORT).show(); } } @Override public void onFailure(@NonNull Call<AllMusicModel> call, @NonNull Throwable t) { Log.e("Error", String.valueOf(t)); } }); } }
关键优化点
- 每个ViewHolder独立持有MediaPlayer,彻底避免全局变量被覆盖导致的音频错乱
- 页面切换时主动停止前一页音频,确保同一时间只有一个音频播放
- 优化MediaPlayer的资源释放逻辑,避免内存泄漏
内容的提问来源于stack exchange,提问作者sahil gill
相关产品推荐
相关产品推荐

