[ZT] 两种特殊的Java容器的类List和Set分析

本文详细介绍了Java中两种特殊容器List和Set的特点与应用场景。List确保元素特定顺序,支持ListIterator双方向遍历;Set不允许重复元素,适用于数据字典等场景。文章对比了ArrayList与LinkedList的不同,以及HashSet、TreeSet和LinkedHashSet的特点。

两种特殊的Java容器的类List和Set分析

时间:2007-11-26 04:38:00   来源:赛迪网技术社区  作者:执木  编辑:chinaitzhe

 

容器类可以大大提高编程效率和编程能力,在Java2中,所有的容器都由SUN公司的Joshua Bloch进行了重新设计,丰富了容器类库的功能。  Java2容器类类库的用途是“保存对象”,它分为两类:  Collection----一组独立的元素,通常这些元素都服从某种规则。List必须保持元素特定的顺序,而Set不能有重复元素。  Map----一组成对的“键值对”对象,即其元素是成对的对象,最典型的应用就是数据字典,并且还有其它广泛的应用。另外,Map可以返回其所有键组成的Set和其所有值组成的Collection,或其键值对组成的Set,并且还可以像数组一样扩展多维Map,只要让Map中键值对的每个“值”是一个Map即可。  1.迭代器  迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。  Java中的Iterator功能比较简单,并且只能单向移动:  (1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。  (2) 使用next()获得序列中的下一个元素。  (3) 使用hasNext()检查序列中是否还有元素。  (4) 使用remove()将迭代器新返回的元素删除。  Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。  2.List的功能方法  List(interface): 次序是List最重要的特点;它确保维护元素特定的顺序。List为Collection添加了许多方法,使得能够向List中间插入与移除元素(只推荐LinkedList使用)。一个List可以生成ListIterator,使用它可以从两个方向遍历List,也可以从List中间插入和删除元素。  ArrayList: 由数组实现的List。它答应对元素进行快速随机访问,但是向List中间插入与移除元素的速度很慢。ListIterator只应该用来由后向前遍历ArrayList,而不是用来插入和删除元素,因为这比LinkedList开销要大很多。  LinkedList: 对顺序访问进行了优化,向List中间插入与删除得开销不大,随机访问则相对较慢(可用ArrayList代替)。它具有方法addFirst()、addLast()、getFirst()、getLast()、removeFirst()、removeLast(),这些方法(没有在任何接口或基类中定义过)使得LinkedList可以当作堆栈、队列和双向队列使用。  3.Set的功能方法  Set(interface): 存入Set的每个元素必须是唯一的,因为Set不保存重复元素。加入Set的Object必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。  HashSet: 为快速查找而设计的Set。存入HashSet的对象必须定义hashCode()。  TreeSet: 保持次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。  LinkedHashSet: 具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。  HashSet采用散列函数对元素进行排序,这是专门为快速查询而设计的;TreeSet采用红黑树的数据结构进行排序元素;LinkedHashSet内部使用散列以加快查询速度,同时使用链表维护元素的次序,使得看起来元素是以插入的顺序保存的。需要注重的是,生成自己的类时,Set需要维护元素的存储顺序,因此要实现Comparable接口并定义compareTo()方法。

package com.weishitech.qichechangtingyinyue.utils; import android.view.View; import android.widget.ImageView; import com.weishitech.qichechangtingyinyue.R; public class ThemeManager { public static final int THEME_BLUE = 0; public static final int THEME_GREEN = 1; public static final int THEME_RED = 2; private int[] backgrounds = { R.mipmap.img_lan_bg, R.mipmap.img_lv_bg, R.mipmap.img_hong_bg }; private int[] background = { R.mipmap.img_lan_mh, R.mipmap.img_lv_mh_bg, R.mipmap.img_hong_mh }; private int[] playIcons = { R.mipmap.img_lan_bf, R.mipmap.img_lv_bf, R.mipmap.img_hong_bf }; private int[] pauseIcons = { R.mipmap.img_lan_zt, R.mipmap.img_lv_zt, R.mipmap.img_hong_zt }; private int currentThemeIndex = 0; /** * 下一个主题(循环) */ public void nextTheme() { currentThemeIndex = (currentThemeIndex + 1) % backgrounds.length; } /** * 设置指定主题 */ public void setTheme(int index) { if (index >= 0 && index < backgrounds.length) { currentThemeIndex = index; } } /** * 应用当前主题到视图 */ public void applyThemeTo(View backgroundView1, View backgroundView2, ImageView iconView, boolean isPlaying) { try { // 更新背景 if (backgroundView1 != null) { backgroundView1.setBackgroundResource(backgrounds[currentThemeIndex]); } if (backgroundView2 != null) { backgroundView2.setBackgroundResource(backgrounds[currentThemeIndex]); } // 更新图标 if (iconView != null) { int resId = isPlaying ? pauseIcons[currentThemeIndex] : playIcons[currentThemeIndex]; iconView.setImageResource(resId); } } catch (Exception e) { e.printStackTrace(); } } public int getCurrentThemeIndex() { return currentThemeIndex; } public int getBackgroundRes() { return backgrounds[currentThemeIndex]; } public int getPauseIconRes() { return pauseIcons[currentThemeIndex]; } public int getPlayIconRes() { return playIcons[currentThemeIndex]; } } package com.weishitech.qichechangtingyinyue.fragment.home; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.PointF; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearSmoothScroller; import androidx.recyclerview.widget.RecyclerView; import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.listener.OnItemClickListener; import com.hfd.common.base.BaseFragment; import com.hfd.common.net.GenericsCallback; import com.hfd.common.net.HttpBuiler; import com.hfd.common.net.JsonGenericsSerializator; import com.hfd.common.net.Url; import com.hfd.common.util.ToastUtil; import com.weishitech.qichechangtingyinyue.MainActivity; import com.weishitech.qichechangtingyinyue.R; import com.weishitech.qichechangtingyinyue.bean.MusicBean; import com.weishitech.qichechangtingyinyue.bean.MusicCache; import com.weishitech.qichechangtingyinyue.bean.NavigationSource; import com.weishitech.qichechangtingyinyue.bean.PlayStatusUpdateEvent; import org.greenrobot.eventbus.EventBus; import com.weishitech.qichechangtingyinyue.fragment.Adapter.PrivateAdapter; import com.weishitech.qichechangtingyinyue.fragment.Adapter.QyAdapter; import com.weishitech.qichechangtingyinyue.fragment.Adapter.SongTopAdapter; import com.weishitech.qichechangtingyinyue.fragment.Adapter.XzAdapter; import com.weishitech.qichechangtingyinyue.fragment.lilv.LiLvFragment; import com.weishitech.qichechangtingyinyue.utils.DisplayUtils; import com.weishitech.qichechangtingyinyue.utils.LeftGravitySnapHelper; import com.weishitech.qichechangtingyinyue.utils.MusicPlayerManager; import com.weishitech.qichechangtingyinyue.utils.OnMultiClickListener; import com.weishitech.qichechangtingyinyue.utils.RotationAnimatorHelper; import com.weishitech.qichechangtingyinyue.utils.ThemeManager; import com.weishitech.qichechangtingyinyue.view.FixedSideSnapHelper; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import okhttp3.Call; /** * 高端语音导航首页 */ public class HomeFragment extends BaseFragment { // UI Views private RecyclerView rv, sr_rv, qy_rv, xz_rv; private ImageView iv_ss, iv_gd, sr_start, qy_start, xz_start, iv_bf; private TextView tv_time, tv_song_name; private LinearLayout line; private RelativeLayout relative,relative1,relative2,relative3; // Managers & Helpers private MusicPlayerManager playerManager; private ThemeManager themeManager; private RotationAnimatorHelper rotationHelper; // private boolean isMainPlaybackActive = false; // 是否由主流程控制播放状态 // Data & State private SongTopAdapter songTopAdapter; private List<MusicBean.DataBean> restList = new ArrayList<>(); private List<MusicBean.DataBean> privateSongList;//私人播放列表字段 private List<MusicBean.DataBean> qySongList;//轻音乐播放列表字段 private List<MusicBean.DataBean> xzSongList;//小众音乐播放列表字段 private GestureDetector gestureDetector; private PrivateAdapter privateAdapter; private boolean isAutoSwitching = false; // 标记是否正在自动切换下一首 // 自动滑动相关 private Handler autoScrollHandler; private Runnable autoScrollRunnable; private boolean isAutoScrollEnabled = true; // 是否启用自动滑动 private long autoScrollInterval = 5000; // 自动滑动间隔(毫秒),默认5秒 private long lastManualScrollTime = 0; // 最后一次手动滑动的时间 private long manualScrollPauseDuration = 10000; // 手动滑动后暂停自动滑动的时间(毫秒),默认10秒 private MainActivity mActivity; private List<MusicBean.DataBean> musicDataList; @Override protected int setLayout() { return R.layout.fragment_home; } @Override protected void initView() { iv_ss = fvbi(R.id.iv_ss); iv_gd = fvbi(R.id.iv_gd); iv_bf = fvbi(R.id.iv_bf); rv = fvbi(R.id.rv); sr_rv = fvbi(R.id.sr_rv); qy_rv = fvbi(R.id.qy_rv); xz_rv = fvbi(R.id.xz_rv); sr_start = fvbi(R.id.sr_start); qy_start = fvbi(R.id.qy_start); xz_start = fvbi(R.id.xz_start); tv_time = fvbi(R.id.tv_time); tv_song_name = fvbi(R.id.tv_song_name); line = fvbi(R.id.line); relative = fvbi(R.id.relative); relative1 = fvbi(R.id.relative1); relative2 = fvbi(R.id.relative2); relative3 = fvbi(R.id.relative3); // 初始化组件 playerManager = MusicPlayerManager.getInstance(); //单例获取 themeManager = new ThemeManager(); rotationHelper = new RotationAnimatorHelper(); // 初始化自动滑动Handler autoScrollHandler = new Handler(Looper.getMainLooper()); // 跑马灯 tv_song_name.setEllipsize(TextUtils.TruncateAt.MARQUEE); tv_song_name.setSingleLine(true); tv_song_name.setSelected(true); tv_song_name.setFocusable(true); tv_song_name.setFocusableInTouchMode(true); setupGestureListener(); // 滑动手势换肤 iv_bf.setImageResource(themeManager.getPlayIconRes()); // 默认显示蓝色“播放”图标 if (NavigationSource.isDirectClick()) { NavigationSource.clear(); // 清理,防止影响下一次 } mActivity = (MainActivity) getActivity(); } @Override protected void initClick() { // 搜索跳转 iv_ss.setOnClickListener(v -> { Bundle bundle = new Bundle(); // 添加私人歌曲列表 if (privateSongList != null && !privateSongList.isEmpty()) { bundle.putSerializable("private_song_list", new ArrayList<>(privateSongList)); } else { bundle.putSerializable("private_song_list", new ArrayList<MusicBean.DataBean>()); } // 添加轻音乐列表 if (qySongList != null && !qySongList.isEmpty()) { bundle.putSerializable("qingyin_song_list", new ArrayList<>(qySongList)); } else { bundle.putSerializable("qingyin_song_list", new ArrayList<MusicBean.DataBean>()); } // 跳转并传参 toClass(SearchActivity.class, bundle); }); iv_gd.setOnClickListener(new OnMultiClickListener() { @Override public void onMultiClick(View v) { mActivity.JumpToPrice(); } }); // 播放/暂停按钮 iv_bf.setOnClickListener(v -> { if (musicDataList.isEmpty()) { ToastUtil.showShortToast("暂无歌曲可播放"); return; } //&& isMainPlaybackActive isMainPlaybackActive = false; isMainPlaybackActive = true; // 标记为主控模式 if (playerManager.isPlaying() ) { playerManager.pause(); } else { int pos = findBestObscuredItem(rv, DisplayUtils.dp2px(requireContext(), 50f)); if (pos == RecyclerView.NO_POSITION) pos = 0; playMusicAtPosition(pos); } updatePlayButtonIcon(); // 只有主控才更新 iv_bf }); relative1.setOnClickListener(new OnMultiClickListener() { @Override public void onMultiClick(View v) { if (privateSongList == null || privateSongList.isEmpty()) { ToastUtil.showShortToast("暂无数据"); return; } // 标记为「非直接来源」 NavigationSource.setSource(NavigationSource.FROM_MUSIC_LIST); Bundle bundle = new Bundle(); bundle.putString("type", "私人专属好歌"); bundle.putSerializable("song_list", new ArrayList<>(privateSongList)); // 拷贝一份 toClass(MusicListActivity.class, bundle); } }); relative2.setOnClickListener(new OnMultiClickListener() { @Override public void onMultiClick(View v) { if (qySongList == null || qySongList.isEmpty()) { ToastUtil.showShortToast("暂无数据"); return; } // 标记为「非直接来源」 NavigationSource.setSource(NavigationSource.FROM_MUSIC_LIST); Bundle bundle = new Bundle(); bundle.putString("type", "轻音乐"); bundle.putSerializable("song_list", new ArrayList<>(qySongList)); toClass(MusicListActivity.class, bundle); } }); relative3.setOnClickListener(new OnMultiClickListener() { @Override public void onMultiClick(View v) { if (xzSongList == null || xzSongList.isEmpty()) { ToastUtil.showShortToast("暂无数据"); return; } // 标记为「非直接来源」 NavigationSource.setSource(NavigationSource.FROM_MUSIC_LIST); Bundle bundle = new Bundle(); bundle.putString("type", "小众音乐"); bundle.putSerializable("song_list", new ArrayList<>(xzSongList)); toClass(MusicListActivity.class, bundle); } }); // 双击歌曲信息区域(relative)时自动向左滑动一位 relative.setOnClickListener(new OnMultiClickListener() { @Override public void onMultiClick(View v) { // 双击时向左滑动一位,并自动播放下一首 scrollToNextItem(true); } }); } @Override protected void initData() { updateTimeGreeting(); musicAppInfo(); setupPlaybackListener(); } /** * 设置播放状态监听器(确保 HomeFragment 的监听器始终生效) */ private void setupPlaybackListener() { playerManager.setOnPlaybackStateChangedListener(new MusicPlayerManager.OnPlaybackStateChangedListener() { @Override public void onPlaying(int position) { // 关键修复:检查当前播放的歌曲是否属于首页列表 // 先检查必要的对象是否已初始化 if (songTopAdapter == null || musicDataList == null || musicDataList.isEmpty()) { // 如果适配器或数据列表未初始化,只更新播放按钮状态 updatePlayButtonIcon(); return; } boolean isFromMainList = !playerManager.isPlayingFromPrivate(); if (isFromMainList && position >= 0 && position < musicDataList.size()) { // 播放的是首页列表中的歌曲,更新首页状态 updatePlayButtonIcon(); songTopAdapter.updatePlayingPosition(position); startRotationForCurrentItem(position); // 更新歌曲信息显示 MusicBean.DataBean currentSong = musicDataList.get(position); if (currentSong != null && tv_song_name != null) { tv_song_name.setText(currentSong.getTitle() + "-" + currentSong.getSinger()); } // 关键修复:发送事件更新tab圆形图标,即使封面为空也要发送 // 这样可以确保当歌曲没有封面时,图标会更新为默认图标,而不是卡在之前的封面 if (currentSong != null) { PlayStatusUpdateEvent event = new PlayStatusUpdateEvent( currentSong.getCover(), // 可能为null或空,但也要发送 currentSong.getTitle(), currentSong.getSinger(), true ); EventBus.getDefault().post(event); } } else { // 播放的是外部列表的歌曲(私人、轻音乐、小众等),清除首页的播放状态 songTopAdapter.updatePlayingPosition(-1); // 清除播放位置 if (rotationHelper != null) { rotationHelper.stopRotation(); // 停止旋转动画 } // 更新其他适配器的状态 String tag = playerManager.getCurrentPlaylistTag(); if ("private".equals(tag) && privateAdapter != null) { int idx = playerManager.getCurrentExternalIndex(); privateAdapter.updatePlayingPosition(idx, true); } } } @Override public void onPaused() { // 先检查必要的对象是否已初始化 if (rotationHelper == null) { updatePlayButtonIcon(); return; } boolean isFromMainList = !playerManager.isPlayingFromPrivate(); if (isFromMainList) { // 暂停的是首页列表中的歌曲 updatePlayButtonIcon(); rotationHelper.stopRotation(); } else { // 暂停的是外部列表的歌曲 rotationHelper.stopRotation(); // 确保停止旋转 // 更新其他适配器的状态 String tag = playerManager.getCurrentPlaylistTag(); if ("private".equals(tag) && privateAdapter != null) { int idx = playerManager.getCurrentExternalIndex(); privateAdapter.updatePlayingPosition(idx, false); } } } @Override public void onCompletion() { android.util.Log.i("MusicPlayerManager", "========== HomeFragment.onCompletion 被调用 =========="); android.util.Log.i("HomeFragment", "========== onCompletion: 歌曲播放完成 - 开始处理 =========="); android.util.Log.i("HomeFragment", "onCompletion: 当前线程=" + Thread.currentThread().getName()); android.util.Log.i("HomeFragment", "onCompletion: isAdded()=" + isAdded() + ", rv=" + (rv != null) + ", musicDataList=" + (musicDataList != null ? musicDataList.size() : "null")); Log.d("HomeFragment", "onCompletion: 歌曲播放完成 - 开始处理"); // 基本状态检查(放宽条件,只要 rv musicDataList 存在即可) if (rv == null) { android.util.Log.w("HomeFragment", "onCompletion: RecyclerView 为 null,跳过"); return; } if (musicDataList == null || musicDataList.isEmpty()) { android.util.Log.w("HomeFragment", "onCompletion: 歌曲列表为空,跳过"); return; } // 检查播放源(只处理主列表) if (playerManager.isPlayingFromPrivate()) { android.util.Log.d("HomeFragment", "onCompletion: 私人音乐播放完成,不触发主列表自动滑动"); return; } // 停止旋转动画(与定时方式保持一致) rotationHelper.stopRotation(); // 确保在主线程执行(与定时方式完全一致) // scrollToNextItem 内部会使用 rv.post() 确保 UI 操作在主线程,所以这里直接调用即可 android.util.Log.i("MusicPlayerManager", "========== 执行自动滑动到下一首 =========="); android.util.Log.i("HomeFragment", "========== onCompletion: 执行自动滑动到下一首 =========="); Log.d("HomeFragment", "onCompletion: 执行自动滑动到下一首,当前线程=" + Thread.currentThread().getName()); scrollToNextItem(true); } @Override public void onError(String errorMsg) { ToastUtil.showShortToast(errorMsg); if (playerManager.isPlayingFromPrivate()) { privateAdapter.clearPlayingState(); } else { updatePlayButtonIcon(); } rotationHelper.stopRotation(); } }); } private void updateTimeGreeting() { Calendar calendar = Calendar.getInstance(); int hour = calendar.get(Calendar.HOUR_OF_DAY); String greeting; if (hour >= 5 && hour < 11) greeting = "HI,早上好"; else if (hour == 11 || hour == 12 || (hour >= 13 && hour < 18)) greeting = "HI,下午好"; else greeting = "HI,晚上好"; tv_time.setText(greeting); } private void musicAppInfo() { HashMap<String, String> map = new HashMap<>(); showDialog(); HttpBuiler.getInfo(Url.music, map).build().execute( new GenericsCallback<MusicBean>(new JsonGenericsSerializator()) { @Override public void onError(Call call, Exception e, int id) { dissmiss(); ToastUtil.showShortToast(e.getMessage()); } @Override public void onResponse(MusicBean response, int id) { dissmiss(); if ("0".equals(response.getCode()) && response.getData() != null && !response.getData().isEmpty()) { restList = response.getData(); // 获取第三条之后的数据(即从索引2开始到末尾) musicDataList = new ArrayList<>(restList.subList(3, restList.size())); // 缓存主歌单 MusicCache.setMainMusicList(musicDataList); setupMusicRecyclerView(); // 在 setupMusicRecyclerView 之后重新设置监听器,因为 PrivateAdapter 可能会覆盖监听器 setupPlaybackListener(); notifyLiLvFragmentRefresh(); // 不再使用定时自动滑动,改为歌曲播放完成后自动滑动 // startAutoScroll(); } else { ToastUtil.showShortToast("暂无歌曲数据"); } } }); } private void setupMusicRecyclerView() { songTopAdapter = new SongTopAdapter(); rv.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)); rv.setAdapter(songTopAdapter); // 设置播放状态回调(用于封面旋转) songTopAdapter.setOnPlayStateChangedListener((position, coverView) -> { rotationHelper.stopRotation(); rotationHelper.startRotation(coverView); }); // 必须在设置 adapter 后再初始化滚动逻辑 setupSnappingAndPlayback(rv, songTopAdapter); // 最后设置数据 songTopAdapter.setList(musicDataList); //点击top条目跳转到歌词页面 songTopAdapter.setOnItemClickListener((position, dataBean) -> { // 标记为「直接点击」来源 NavigationSource.setSource(NavigationSource.DIRECT_CLICK); // 创建 Bundle 传递数据 Bundle bundle = new Bundle(); bundle.putString("title", dataBean.getTitle()); bundle.putString("singer", dataBean.getSinger()); bundle.putString("cover_url", dataBean.getCover()); bundle.putString("music_url", dataBean.getMusic()); bundle.putString("time", dataBean.getSongTime()); bundle.putInt("position", position); bundle.putInt("total_count", musicDataList.size()); // 跳转到 LyricsActivity toClass(LyricsActivity.class, bundle); }); //私人音乐适配器 // 从第三个元素(索引=2)开始,取最多20首歌曲 int start = 3; // 第三个元素的索引 int end = Math.min(start + 20, musicDataList.size()); // 最多取20首,且不能越界 if (start >= musicDataList.size()) { privateSongList = new ArrayList<>(); // 防止越界 ToastUtil.showShortToast("起始位置超出列表范围"); } else { privateSongList = new ArrayList<>(musicDataList.subList(start, end)); } privateAdapter = new PrivateAdapter(); privateAdapter.setMainPlayButtonUpdater(isPlaying -> { Log.d("11111111",""+isPlaying); iv_bf.setImageResource(isPlaying ? themeManager.getPauseIconRes() : themeManager.getPlayIconRes()); }); // 设置横向 Grid 布局:每行3个 GridLayoutManager gridLayoutManager = new GridLayoutManager(requireContext(), 3, RecyclerView.HORIZONTAL, false); sr_rv.setLayoutManager(gridLayoutManager); sr_rv.setAdapter(privateAdapter); privateAdapter.setList(privateSongList); // <<< 添加吸附效果 >>> new LeftGravitySnapHelper().attachToRecyclerView(sr_rv); privateAdapter.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) { // 创建 Bundle 传递数据 Bundle bundle = new Bundle(); bundle.putString("title", privateSongList.get(position).getTitle()); bundle.putString("singer", privateSongList.get(position).getSinger()); bundle.putString("cover_url", privateSongList.get(position).getCover()); bundle.putString("music_url", privateSongList.get(position).getMusic()); bundle.putString("time", privateSongList.get(position).getSongTime()); bundle.putInt("position", position); bundle.putInt("total_count", privateSongList.size()); // 传递source_list,用于上下首切换 bundle.putSerializable("source_list", new ArrayList<>(privateSongList)); // 传递播放列表标签 bundle.putString("playlist_tag", "private"); // 跳转到 LyricsActivity toClass(LyricsActivity.class, bundle); } }); //轻音乐 // 确保 musicDataList 不为 null 且有数据 if (musicDataList == null || musicDataList.isEmpty()) { return; } int qystart = 5; int count = 6; int qyend = Math.min(qystart + count, musicDataList.size()); qySongList = new ArrayList<>(musicDataList.subList(qystart, qyend)); QyAdapter qyAdapter = new QyAdapter(); // 设置横向 Grid 布局:每行3个 GridLayoutManager gridLayoutManagers = new GridLayoutManager(requireContext(), 2); qy_rv.setLayoutManager(gridLayoutManagers); qy_rv.setAdapter(qyAdapter); qyAdapter.setList(qySongList); qyAdapter.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) { // 创建 Bundle 传递数据 Bundle bundle = new Bundle(); bundle.putString("title", qySongList.get(position).getTitle()); bundle.putString("singer", qySongList.get(position).getSinger()); bundle.putString("cover_url", qySongList.get(position).getCover()); bundle.putString("music_url", qySongList.get(position).getMusic()); bundle.putString("time", qySongList.get(position).getSongTime()); bundle.putInt("position", position); bundle.putInt("total_count", qySongList.size()); // 传递source_list,用于上下首切换 bundle.putSerializable("source_list", new ArrayList<>(qySongList)); // 传递播放列表标签 bundle.putString("playlist_tag", "qingyin"); // 跳转到 LyricsActivity toClass(LyricsActivity.class, bundle); } }); //小众音乐 // 确保 musicDataList 不为 null 且有数据 if (musicDataList == null || musicDataList.isEmpty()) { return; } int xzstart = 8; int xzcount = 6; int xzend = Math.min(xzstart + xzcount, musicDataList.size()); xzSongList = new ArrayList<>(musicDataList.subList(xzstart, xzend)); XzAdapter xzAdapter = new XzAdapter(); // 设置横向 Grid 布局:每行3个 xz_rv.setLayoutManager(new LinearLayoutManager(requireContext(),LinearLayoutManager.HORIZONTAL, false)); xz_rv.setAdapter(xzAdapter); xzAdapter.setList(xzSongList); // <<< 添加吸附效果 >>> new LeftGravitySnapHelper().attachToRecyclerView(xz_rv); xzAdapter.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) { // 创建 Bundle 传递数据 Bundle bundle = new Bundle(); bundle.putString("title", xzSongList.get(position).getTitle()); bundle.putString("singer", xzSongList.get(position).getSinger()); bundle.putString("cover_url", xzSongList.get(position).getCover()); bundle.putString("music_url", xzSongList.get(position).getMusic()); bundle.putString("time", xzSongList.get(position).getSongTime()); bundle.putInt("position", position); bundle.putInt("total_count", xzSongList.size()); // 传递source_list,用于上下首切换 bundle.putSerializable("source_list", new ArrayList<>(xzSongList)); // 传递播放列表标签 bundle.putString("playlist_tag", "xiaozhong"); // 跳转到 LyricsActivity toClass(LyricsActivity.class, bundle); } }); } private void setupSnappingAndPlayback(RecyclerView rv, SongTopAdapter adapter) { LinearLayoutManager layoutManager = (LinearLayoutManager) rv.getLayoutManager(); if (layoutManager == null) return; int fixedTargetX = DisplayUtils.dp2px(requireContext(), 50f); FixedSideSnapHelper snapHelper = new FixedSideSnapHelper(fixedTargetX); snapHelper.attachToRecyclerView(rv); AtomicInteger lastPlayedPosition = new AtomicInteger(RecyclerView.NO_POSITION); final boolean[] isFirstLayoutDone = {false}; // <<< 添加标志位 // 延迟标记“首次布局已完成” rv.post(() -> isFirstLayoutDone[0] = true); rv.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // 关键:只有完成首次布局后才允许自动播放 if (!isFirstLayoutDone[0]) { return; } // 如果是自动切换,不触发滚动监听器的自动播放逻辑 if (isAutoSwitching) { return; } int pos = findBestObscuredItem(recyclerView, fixedTargetX); if (pos != RecyclerView.NO_POSITION && pos != lastPlayedPosition.get()) { final int finalPos = pos; // 使用 post 延迟执行,避免在 layout 过程中更改数据 rv.post(() -> { playMusicAtPosition(finalPos); lastPlayedPosition.set(finalPos); }); } dispatchVisualFeedback(recyclerView, adapter); } @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); if (layoutManager == null) return; // 如果是自动切换,不触发滚动状态变化的自动播放逻辑 if (isAutoSwitching) { Log.d("HomeFragment", "onScrollStateChanged: isAutoSwitching=true, newState=" + newState); // 不在这里清除标志,让延迟任务来处理 return; } int fixedTargetX = DisplayUtils.dp2px(requireContext(), 50f); switch (newState) { case RecyclerView.SCROLL_STATE_DRAGGING: // 用户开始手动拖拽,暂停当前播放 // 滑动开始了,暂停当前播放 if (playerManager.isPlaying()) { playerManager.pause(); rotationHelper.stopRotation(); updatePlayButtonIcon(); // 显示"暂停"图标 } // 记录手动滑动时间(用于歌曲播放完成时判断是否在暂停期) if (!isAutoSwitching) { lastManualScrollTime = System.currentTimeMillis(); // 不再需要停止定时器,因为使用歌曲播放完成方式 // stopAutoScroll(); } break; case RecyclerView.SCROLL_STATE_SETTLING: // 滑动中,暂停当前播放 if (playerManager.isPlaying()) { playerManager.pause(); rotationHelper.stopRotation(); updatePlayButtonIcon(); // 显示"暂停"图标 } break; case RecyclerView.SCROLL_STATE_IDLE: // 滑动结束,找到应该播放的 item 并自动播放 // 如果是自动切换,不触发这里的逻辑(避免覆盖自动滑动的歌曲信息) if (isAutoSwitching) { // 自动切换时,确保歌曲信息已更新 int targetPos = findBestObscuredItem(recyclerView, fixedTargetX); if (targetPos != RecyclerView.NO_POSITION && targetPos < musicDataList.size()) { MusicBean.DataBean bean = musicDataList.get(targetPos); tv_song_name.setText(bean.getTitle() + "-" + bean.getSinger()); } break; } // 手动滑动结束,不再启动定时器(使用歌曲播放完成方式) int targetPos = findBestObscuredItem(recyclerView, fixedTargetX); if (targetPos != RecyclerView.NO_POSITION) { playMusicAtPosition(targetPos); // 这个方法会播放音乐 + 更新 UI + 开始旋转 } else { // 如果没找到合适的位置,至少恢复状态 updatePlayButtonIcon(); } break; } } }); setupOneWayScroll(rv, requireContext()); } private int findBestObscuredItem(RecyclerView rv, int fuzzyRightEdge) { LinearLayoutManager lm = (LinearLayoutManager) rv.getLayoutManager(); if (lm == null) return RecyclerView.NO_POSITION; int bestPos = RecyclerView.NO_POSITION; float minDiff = Float.MAX_VALUE; for (int i = 0; i < lm.getChildCount(); i++) { View child = lm.getChildAt(i); if (child == null) continue; int left = lm.getDecoratedLeft(child); int right = lm.getDecoratedRight(child); int width = right - left; if (right <= 0 || left >= fuzzyRightEdge) continue; // 无交集 int overlapStart = Math.max(left, 0); int overlapEnd = Math.min(right, fuzzyRightEdge); int overlapWidth = Math.max(0, overlapEnd - overlapStart); float coveredRatio = (float) overlapWidth / width; float diff = Math.abs(coveredRatio - 0.5f); if (coveredRatio >= 0.3f && coveredRatio <= 0.7f && diff < minDiff) { minDiff = diff; bestPos = lm.getPosition(child); } } return bestPos; } @SuppressLint("SetTextI18n") private void playMusicAtPosition(int position) { if (position == RecyclerView.NO_POSITION || position >= musicDataList.size()) return; MusicBean.DataBean bean = musicDataList.get(position); iv_bf.setImageResource(themeManager.getPauseIconRes()); tv_song_name.setText(bean.getTitle() + "-" + bean.getSinger()); nextSkin(); // 每次播放新歌就换主题 rv.post(() -> { }); songTopAdapter.updatePlayingPosition(position); playerManager.play(requireContext(), position, bean.getMusic()); PlayStatusUpdateEvent event = new PlayStatusUpdateEvent( bean.getCover(), bean.getTitle(), bean.getSinger(), true ); EventBus.getDefault().post(event); //使用 post() 延迟更新 adapter,避免在 layout 过程中修改 // rv.post(() -> { // // // // 同时更新底部显示 // // // }); // updatePlayButtonIcon(); } private void playNextSong() { int currentPos = playerManager.getCurrentPlayingPosition(); int nextPos = currentPos + 1; if (nextPos >= musicDataList.size()) { ToastUtil.showShortToast("已播放完全部歌曲"); updatePlayButtonIcon(); // 确保按钮变回"播放" return; } Log.d("HomeFragment", "playNextSong: currentPos=" + currentPos + ", nextPos=" + nextPos); // 设置自动切换标志,防止滚动监听器干扰 isAutoSwitching = true; // 先更新播放 UI(但不更新 adapter),避免延迟 MusicBean.DataBean bean = musicDataList.get(nextPos); iv_bf.setImageResource(themeManager.getPauseIconRes()); tv_song_name.setText(bean.getTitle() + "-" + bean.getSinger()); nextSkin(); playerManager.play(requireContext(), nextPos, bean.getMusic()); PlayStatusUpdateEvent event = new PlayStatusUpdateEvent( bean.getCover(), bean.getTitle(), bean.getSinger(), true ); EventBus.getDefault().post(event); // 立即执行平滑滚动动画 rv.post(() -> { scrollToTriggerPosition(nextPos, rv); }); // 滚动完成后更新 adapter 位置(延迟以避免中断滚动) rv.postDelayed(() -> { songTopAdapter.updatePlayingPosition(nextPos); }, 600); // 延迟清除自动切换标志 rv.postDelayed(() -> { isAutoSwitching = false; }, 1000); } /** * 向左滑动一位(自动滑动到下一个item) * @param autoPlay 是否自动播放下一首歌曲 */ public void scrollToNextItem(boolean autoPlay) { if (rv == null || musicDataList == null || musicDataList.isEmpty()) { ToastUtil.showShortToast("暂无歌曲数据"); return; } LinearLayoutManager lm = (LinearLayoutManager) rv.getLayoutManager(); if (lm == null) { Log.e("HomeFragment", "scrollToNextItem: LayoutManager is null!"); return; } // 找到当前显示的位置 int fixedTargetX = DisplayUtils.dp2px(requireContext(), 50f); int currentPos = findBestObscuredItem(rv, fixedTargetX); // 如果找不到当前位置,尝试使用播放器当前的位置 if (currentPos == RecyclerView.NO_POSITION) { currentPos = playerManager.getCurrentPlayingPosition(); if (currentPos == RecyclerView.NO_POSITION) { currentPos = 0; // 默认从第一个开始 } } // 计算下一个位置 int nextPos = currentPos + 1; // 检查是否超出范围 // 如果 autoPlay=true(自动播放),则循环回到第一首 // 如果 autoPlay=false(手动调用),则提示并返回 if (nextPos >= musicDataList.size()) { if (autoPlay) { // 自动播放时循环回到第一首 nextPos = 0; } else { // 手动调用时提示 ToastUtil.showShortToast("已经是最后一首歌曲"); return; } } // 将 nextPos 设为 final,以便在 lambda 中使用 final int finalNextPos = nextPos; Log.d("HomeFragment", "scrollToNextItem: 当前位置=" + currentPos + ", 下一个位置=" + finalNextPos + ", autoPlay=" + autoPlay); // 设置自动切换标志,防止滚动监听器干扰 isAutoSwitching = true; // 更新歌曲信息显示(无论是否自动播放都要更新) MusicBean.DataBean bean = musicDataList.get(finalNextPos); tv_song_name.setText(bean.getTitle() + "-" + bean.getSinger()); // 如果自动播放,播放下一首 if (autoPlay) { iv_bf.setImageResource(themeManager.getPauseIconRes()); nextSkin(); playerManager.play(requireContext(), finalNextPos, bean.getMusic()); PlayStatusUpdateEvent event = new PlayStatusUpdateEvent( bean.getCover(), bean.getTitle(), bean.getSinger(), true ); EventBus.getDefault().post(event); } // 执行平滑滚动(确保 RecyclerView 已经准备好) rv.post(() -> { // 确保 RecyclerView 已经布局完成 if (rv.getLayoutManager() != null && rv.getChildCount() > 0) { android.util.Log.i("HomeFragment", "========== 开始执行滚动动画,目标位置=" + finalNextPos + " =========="); scrollToTriggerPosition(finalNextPos, rv); } else { // RecyclerView 还没准备好,延迟执行 android.util.Log.w("HomeFragment", "RecyclerView 未准备好,延迟执行滚动"); rv.postDelayed(() -> { if (rv.getLayoutManager() != null) { android.util.Log.i("HomeFragment", "========== 延迟执行滚动动画,目标位置=" + finalNextPos + " =========="); scrollToTriggerPosition(finalNextPos, rv); } }, 100); } }); // 滚动完成后更新 adapter 位置歌曲信息 rv.postDelayed(() -> { songTopAdapter.updatePlayingPosition(finalNextPos); // 确保歌曲信息已更新(防止被其他逻辑覆盖) if (finalNextPos < musicDataList.size()) { MusicBean.DataBean currentBean = musicDataList.get(finalNextPos); tv_song_name.setText(currentBean.getTitle() + "-" + currentBean.getSinger()); } }, 600); // 延迟清除自动切换标志 rv.postDelayed(() -> { isAutoSwitching = false; }, 1000); } /** * 向左滑动一位(不自动播放) */ public void scrollToNextItem() { scrollToNextItem(false); } private void scrollToTriggerPosition(int targetPos, RecyclerView rv) { LinearLayoutManager lm = (LinearLayoutManager) rv.getLayoutManager(); if (lm == null) { android.util.Log.e("HomeFragment", "scrollToTriggerPosition: LayoutManager is null!"); return; } // 检查目标位置是否有效 if (targetPos < 0 || targetPos >= musicDataList.size()) { android.util.Log.e("HomeFragment", "scrollToTriggerPosition: 目标位置无效,targetPos=" + targetPos + ", 列表大小=" + musicDataList.size()); return; } android.util.Log.i("HomeFragment", "========== scrollToTriggerPosition: 开始平滑滚动到位置 " + targetPos + " =========="); int targetX = DisplayUtils.dp2px(requireContext(), 50f); LinearSmoothScroller scroller = new LinearSmoothScroller(requireContext()) { @Override public PointF computeScrollVectorForPosition(int targetPosition) { PointF vector = lm.computeScrollVectorForPosition(targetPosition); android.util.Log.d("HomeFragment", "computeScrollVectorForPosition: targetPosition=" + targetPosition + ", vector=" + vector); return vector; } @Override public int calculateDxToMakeVisible(View view, int snapPreference) { int left = lm.getDecoratedLeft(view); int right = lm.getDecoratedRight(view); int center = (left + right) / 2; int dx = targetX - center; android.util.Log.d("HomeFragment", "calculateDxToMakeVisible: view位置 left=" + left + ", right=" + right + ", center=" + center + ", 需要移动dx=" + dx); return dx; } @Override protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { // 滚动速度,值越小越快(与定时方式保持一致) return 100f / displayMetrics.densityDpi; } @Override protected void onStart() { super.onStart(); android.util.Log.i("HomeFragment", "========== LinearSmoothScroller.onStart() =========="); } @Override protected void onStop() { super.onStop(); android.util.Log.i("HomeFragment", "========== LinearSmoothScroller.onStop() =========="); } }; scroller.setTargetPosition(targetPos); try { lm.startSmoothScroll(scroller); android.util.Log.i("HomeFragment", "========== scrollToTriggerPosition: ✓ 已调用 startSmoothScroll,目标位置=" + targetPos + " =========="); } catch (Exception e) { android.util.Log.e("HomeFragment", "scrollToTriggerPosition: 调用 startSmoothScroll 失败", e); // 如果平滑滚动失败,尝试直接滚动 lm.scrollToPositionWithOffset(targetPos, targetX); android.util.Log.w("HomeFragment", "scrollToTriggerPosition: 使用 scrollToPositionWithOffset 作为备选方案"); } } private void dispatchVisualFeedback(RecyclerView rv, SongTopAdapter adapter) { LinearLayoutManager lm = (LinearLayoutManager) rv.getLayoutManager(); if (lm == null) return; int targetX = DisplayUtils.dp2px(requireContext(), 100f); for (int i = 0; i < rv.getChildCount(); i++) { View child = rv.getChildAt(i); if (child == null) continue; int centerX = (lm.getDecoratedLeft(child) + lm.getDecoratedRight(child)) / 2; float distance = Math.abs(centerX - targetX); if (distance > 600) continue; // float alpha = 1.0f - Math.min(1.0f, distance / 300f); // float scale = 0.8f + 0.2f * (1.0f - Math.min(1.0f, distance / 200f)); // child.setAlpha(alpha); // child.setScaleX(scale); // child.setScaleY(scale); } } private void setupOneWayScroll(RecyclerView rv, Context context) { final boolean[] hasScrolledLeft = {false}; final float[] startX = {0f}; rv.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() { @Override public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent e) { switch (e.getAction()) { case MotionEvent.ACTION_DOWN: startX[0] = e.getX(); break; case MotionEvent.ACTION_MOVE: float dx = e.getX() - startX[0]; if (dx < -20 && !hasScrolledLeft[0]) { hasScrolledLeft[0] = true; } if (hasScrolledLeft[0] && dx > 15) { Toast.makeText(context, "暂只支持左滑操作", Toast.LENGTH_SHORT).show(); return true; } break; } return false; } }); } private void setupGestureListener() { gestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { float diffX = e2.getX() - e1.getX(); if (Math.abs(diffX) > Math.abs(e2.getY() - e1.getY())) { if (Math.abs(diffX) > 100 && Math.abs(velocityX) > 100) { nextSkin(); // 滑动换肤 return true; } } return false; } }); View.OnTouchListener touchListener = (v, event) -> gestureDetector.onTouchEvent(event); line.setOnTouchListener(touchListener); relative.setOnTouchListener(touchListener); } private void nextSkin() { themeManager.nextTheme(); applyCurrentTheme(); // ToastUtil.showShortToast("切换到主题 " + (themeManager.getCurrentThemeIndex() + 1)); } private void applyCurrentTheme() { if (!isAdded()) return; // 只负责换肤:背景等 themeManager.applyThemeTo(line, relative, null, false); // 单独设置播放按钮图标,使用动态资源 // 关键修复:只有当播放的是首页列表中的歌曲时,才显示"暂停"状态 boolean isFromMainList = !playerManager.isPlayingFromPrivate(); boolean isPlaying = playerManager.isPlaying(); boolean shouldShowPause = isFromMainList && isPlaying; iv_bf.setImageResource(shouldShowPause ? themeManager.getPauseIconRes() : themeManager.getPlayIconRes()); } /** * 更新主播放按钮图标(根据实际播放状态) * 关键修复:只有当播放的是首页列表中的歌曲时,才显示"暂停"状态 * 如果播放的是外部列表的歌曲,显示"播放"状态(待播放) */ private void updatePlayButtonIcon() { if (!isAdded() || iv_bf == null) return; // 检查当前播放的歌曲是否属于首页列表 boolean isFromMainList = !playerManager.isPlayingFromPrivate(); boolean isPlaying = playerManager.isPlaying(); // 只有当播放的是首页列表中的歌曲且正在播放时,才显示"暂停"状态 // 其他情况(播放外部列表歌曲或未播放)都显示"播放"状态(待播放) boolean shouldShowPause = isFromMainList && isPlaying; Log.d("HomeFragment", "🔄 updatePlayButtonIcon: isPlaying=" + isPlaying + ", isFromMainList=" + isFromMainList + ", shouldShowPause=" + shouldShowPause + ", currentTheme=" + themeManager.getCurrentThemeIndex()); iv_bf.setImageResource(shouldShowPause ? themeManager.getPauseIconRes() : themeManager.getPlayIconRes()); } private void startRotationForCurrentItem(int position) { // 先停止任何正在进行的动画 rotationHelper.stopRotation(); // 获取 ViewHolder RecyclerView.ViewHolder vh = rv.findViewHolderForAdapterPosition(position); if (vh == null) { // item 当前不可见,可以延迟执行或跳过 return; } ImageView coverView = vh.itemView.findViewById(R.id.iv_song_logo); if (coverView != null) { rotationHelper.startRotation(coverView); // 开始旋转 } } /** * 启动自动滑动 */ private void startAutoScroll() { if (!isAutoScrollEnabled || musicDataList == null || musicDataList.isEmpty()) { return; } // 检查是否在手动滑动后的暂停期内 if (lastManualScrollTime > 0) { long timeSinceManualScroll = System.currentTimeMillis() - lastManualScrollTime; if (timeSinceManualScroll < manualScrollPauseDuration) { // 还在暂停期内,延迟启动 autoScrollHandler.postDelayed(() -> { if (isAutoScrollEnabled && musicDataList != null && !musicDataList.isEmpty()) { startAutoScroll(); } }, manualScrollPauseDuration - timeSinceManualScroll); return; } } // 如果已经在运行,先停止 stopAutoScroll(); autoScrollRunnable = new Runnable() { @Override public void run() { if (!isAdded() || rv == null || musicDataList == null || musicDataList.isEmpty()) { return; } // 检查是否在手动滑动后的暂停期内 if (lastManualScrollTime > 0) { long timeSinceManualScroll = System.currentTimeMillis() - lastManualScrollTime; if (timeSinceManualScroll < manualScrollPauseDuration) { // 还在暂停期内,延迟执行 if (autoScrollHandler != null && autoScrollRunnable != null) { autoScrollHandler.postDelayed(autoScrollRunnable, manualScrollPauseDuration - timeSinceManualScroll); } return; } lastManualScrollTime = 0; // 重置 } // 停止旋转动画(与歌曲播放完成时保持一致) rotationHelper.stopRotation(); // 使用 post 确保在主线程执行,避免状态冲突(与歌曲播放完成时保持一致) rv.post(() -> { // 执行滑动并自动播放下一首 scrollToNextItem(true); }); // 继续下一次定时任务 if (autoScrollHandler != null && autoScrollRunnable != null) { autoScrollHandler.postDelayed(autoScrollRunnable, autoScrollInterval); } } }; // 延迟启动第一次滑动 autoScrollHandler.postDelayed(autoScrollRunnable, autoScrollInterval); Log.d("HomeFragment", "自动滑动已启动,间隔=" + autoScrollInterval + "ms"); } /** * 停止自动滑动 */ private void stopAutoScroll() { if (autoScrollHandler != null && autoScrollRunnable != null) { autoScrollHandler.removeCallbacks(autoScrollRunnable); autoScrollRunnable = null; Log.d("HomeFragment", "自动滑动已停止"); } } @Override public void onDestroy() { // 不再需要停止定时器(使用歌曲播放完成方式) // stopAutoScroll(); if (autoScrollHandler != null) { autoScrollHandler.removeCallbacksAndMessages(null); // 清理 Handler } playerManager.release(); rotationHelper.stopRotation(); super.onDestroy(); } @Override public void onPause() { super.onPause(); // 页面不可见时不再需要停止定时器(使用歌曲播放完成方式) // stopAutoScroll(); } @Override public void onResume() { super.onResume(); Log.d("HomeFragment", "onResume called, source = " + NavigationSource.getSource()); // 重新设置播放状态监听器,确保 HomeFragment 的监听器始终生效 // 因为 PrivateAdapter 等可能会覆盖监听器 setupPlaybackListener(); // 关键修复:检查当前播放的歌曲是否属于首页列表 // 先检查必要的对象是否已初始化 if (songTopAdapter == null || musicDataList == null || musicDataList.isEmpty()) { // 如果适配器或数据列表未初始化,只更新播放按钮状态 updatePlayButtonIcon(); NavigationSource.clear(); return; } boolean isFromMainList = !playerManager.isPlayingFromPrivate(); if (isFromMainList && playerManager.isPlaying()) { // 播放的是首页列表中的歌曲 int currentPos = playerManager.getCurrentPlayingPosition(); if (currentPos >= 0 && currentPos < musicDataList.size()) { updatePlayButtonIcon(); songTopAdapter.updatePlayingPosition(currentPos); // 更新歌曲信息显示 MusicBean.DataBean currentSong = musicDataList.get(currentPos); if (currentSong != null && tv_song_name != null) { tv_song_name.setText(currentSong.getTitle() + "-" + currentSong.getSinger()); } // 只有是从「直接点击」进入 LyricsActivity 再返回,才执行滚动高亮 if (NavigationSource.isDirectClick()) { applyCurrentTheme(); syncToCurrentPlayingItem(currentPos); } } } else { // 播放的是外部列表的歌曲或未播放,清除首页的播放状态 songTopAdapter.updatePlayingPosition(-1); // 清除播放位置 if (rotationHelper != null) { rotationHelper.stopRotation(); // 停止旋转动画 } updatePlayButtonIcon(); // 更新按钮状态 // 可选:清除标记,避免下次误判 NavigationSource.clear(); } // 不再使用定时自动滑动,改为歌曲播放完成后自动滑动 // startAutoScroll(); } /** * 滚动并高亮当前正在播放的歌曲 */ private void syncToCurrentPlayingItem(int position) { if (songTopAdapter == null || rv == null || musicDataList == null || position >= musicDataList.size()) { return; } LinearLayoutManager layoutManager = (LinearLayoutManager) rv.getLayoutManager(); if (layoutManager == null) return; // 目标 x 坐标:距离左边 50dp int targetX = DisplayUtils.dp2px(requireContext(), 50f); LinearSmoothScroller scroller = new LinearSmoothScroller(requireContext()) { @Override public PointF computeScrollVectorForPosition(int targetPosition) { return layoutManager.computeScrollVectorForPosition(targetPosition); } @Override public int calculateDxToMakeVisible(View view, int snapPreference) { // 正确调用:通过 layoutManager 调用 int left = layoutManager.getDecoratedLeft(view); int right = layoutManager.getDecoratedRight(view); int center = (left + right) / 2; // 返回需要移动的距离 return targetX - center; } @Override protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { // 控制滚动速度:越小越快 return 100f / displayMetrics.densityDpi; // 可调 } }; scroller.setTargetPosition(position); layoutManager.startSmoothScroll(scroller); // 延迟查找 ViewHolder 并启动旋转 rv.postDelayed(() -> { RecyclerView.ViewHolder vh = rv.findViewHolderForAdapterPosition(position); if (vh != null) { ImageView coverView = vh.itemView.findViewById(R.id.iv_song_logo); if (coverView != null) { rotationHelper.stopRotation(); rotationHelper.startRotation(coverView); } } }, 350); // 等待滚动接近完成 } private void notifyLiLvFragmentRefresh() { // 假设你通过某种方式获取到 LiLvFragment 实例 // 方法一:通过 Activity 管理 Fragment lilvFragment = getParentFragmentManager().findFragmentByTag("LILV_FRAGMENT"); if (lilvFragment instanceof LiLvFragment) { ((LiLvFragment) lilvFragment).refreshData(); } } } 切换主题多加一个 private int[] background = { R.mipmap.img_lan_mh, R.mipmap.img_lv_mh_bg, R.mipmap.img_hong_mh };
12-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值