Android开发如何在两个Adapter间共享ArrayList歌曲列表数据
Android双Adapter共享本地歌曲集合实现方案
核心思路:不要在Adapter内部独立持有数据副本,将唯一的数据集实例托管在页面宿主(Activity/Fragment)层,两个Adapter通过构造方法持有同一份集合的引用即可,既不会产生额外内存开销,也能保证数据完全一致。
具体实现步骤
1. 上移数据集持有逻辑到宿主层
把你原来写的fetchSongs()方法、歌曲集合songs都放到承载RecyclerView和引导页ViewPager的Activity/Fragment中,作为页面级成员变量,保证整个页面生命周期内只有一份songs实例:
// 宿主Activity/Fragment 内的成员变量 private ArrayList<ModelClass> songs; private Adapter songRvAdapter; private SlideAdapter onboardingPagerAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化空集合 songs = new ArrayList<>(); // 执行本地音频查询 fetchSongs(); } // 你原有的MediaStore查询逻辑保持不变,查询结果直接填充到上面的songs成员变量即可 private void fetchSongs() { // ContentResolver查询、Cursor遍历、数据封装的原有逻辑不变 // 注意不要在方法内部new新的ArrayList,所有查到的歌曲都add进全局的songs集合 }
2. 给两个Adapter统一增加集合构造参数
你原来给RecyclerView用的歌曲Adapter本身已经接收songs参数,保持原有逻辑不用改:
// RecyclerView对应歌曲列表Adapter public class Adapter extends RecyclerView.Adapter<Adapter.SongViewHolder> { private final ArrayList<ModelClass> localSongs; public Adapter(ArrayList<ModelClass> songs) { this.localSongs = songs; } // 原有onCreateViewHolder、onBindViewHolder、getItemCount逻辑完全不变 }
修改引导页用的SlideAdapter,同样在构造方法中接收歌曲集合参数:
public class SlideAdapter extends PagerAdapter { private final Context context; private final ArrayList<ModelClass> localSongs; // 新增songs作为构造入参 public SlideAdapter(Context context, ArrayList<ModelClass> songs) { this.context = context; this.localSongs = songs; } @NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { View itemView = LayoutInflater.from(context).inflate(/* 你的引导页布局id */, container, false); if (position == 2) { // 这里直接访问localSongs即可,和RecyclerView拿到的是完全相同的同一份数据 // 示例:如果要展示扫描到的歌曲总数 // TextView countTip = itemView.findViewById(R.id.tv_song_count); // countTip.setText("已扫描到" + localSongs.size() + "首本地音频"); } // 其他position的引导页加载逻辑保持原有写法不变 container.addView(itemView); return itemView; } // 原有destroyItem、getCount、isViewFromObject等方法逻辑完全不变 }
3. 宿主层初始化Adapter时传入同一份songs实例
等fetchSongs()完成数据填充后,初始化两个Adapter时都传入全局的songs集合即可:
// 宿主页面内,歌曲查询完成后调用初始化方法 private void initPageWidgets() { // 初始化歌曲列表 RecyclerView songRv = findViewById(R.id.rv_song_list); songRv.setLayoutManager(new LinearLayoutManager(this)); songRvAdapter = new Adapter(songs); songRv.setAdapter(songRvAdapter); // 初始化引导页ViewPager ViewPager onboardingVp = findViewById(R.id.vp_onboarding); onboardingPagerAdapter = new SlideAdapter(this, songs); onboardingVp.setAdapter(onboardingPagerAdapter); }
注意事项
- 如果你是用子线程/协程/CursorLoader异步查询音频,必须等查询完成、songs集合填充完毕后再初始化Adapter,或者先初始化Adapter,等数据加载完成后同时调用两个Adapter的
notifyDataSetChanged()刷新,避免拿到空数据。 - 不要在任何一个Adapter内部重新new ArrayList拷贝songs数据,只要持有构造方法传入的引用即可,后续songs发生增删改时,只要调用对应Adapter的notify方法,两个控件会同步展示最新数据,不会出现不一致问题。
- 不要用静态全局变量存储songs实现共享,会引发内存泄漏、生命周期失控问题,宿主持有+构造传参是最稳妥的实现方式。
内容的提问来源于stack exchange,提问作者Channel one
相关产品推荐
相关产品推荐

