上篇博客讲到如何获取手机中所有歌曲的信息。本文就把上篇获取到的歌曲按照歌手名字分类。用一个ExpandableListView显示出来。
MainActivity .java
public class MainActivity extends AppCompatActivity { private static List<MusicLoader.MusicInfo> musicList = new ArrayList<MusicLoader.MusicInfo>(); private ExpandableListView groupLvSongs; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initEvent(); } private void initEvent() { // 这是获取musicList,与本篇博客主题无关,大家只需要知道musicList代表所有歌曲,它的每一项都包含一首歌的所有信息 musicList = MusicLoader.instance(getContentResolver()).getMusicList(); // 设置适配器,给listview提供数据 groupLvSongs.setAdapter(new myExadapter(MainActivity.this, musicList)); } private void initView() { groupLvSongs = (ExpandableListView) findViewById(R.id.groupLvSongs); } /** * 按歌手分类的listview 对应的Adapter,自定义ExpandableListView的适配器 * getGroupId()getChildId()hasStableIds()isChildSelectable暂时都默认自动生成的, * 最主要是getGroupView(),getChildView()方法 */ class myExadapter extends BaseExpandableListAdapter { //在获取view的时候需要context private Context context; //所有歌曲 private List<MusicInfo> musicList = new ArrayList<MusicInfo>(); //记录各个歌手名字 private List<String> groupName = new ArrayList<String>(); //按歌手名字分类后的所有歌曲 private List<List<MusicInfo>> musicGroupBySinger = new ArrayList<List<MusicInfo>>(); myExadapter(Context context, List<MusicInfo> group) { this.context = context; musicList = group; sortByArtistName(); } // 根据歌手分类最终获得 musicGroupBySinger private void sortByArtistName() { // 第一个特殊 groupName.add(musicList.get(0).getArtist()); List<MusicInfo> musicListWithSameSinger = new ArrayList<MusicInfo>(); musicListWithSameSinger.add(musicList.get(0)); musicGroupBySinger.add(musicListWithSameSinger); for (int i = 1; i < musicList.size(); i++) { boolean flag = false; for (int j = 0; j < groupName.size(); j++) { // if该歌手名字已经存在 if (musicList.get(i).getArtist().equals(groupName.get(j))) { flag = true; musicGroupBySinger.get(j).add(musicList.get(i)); break; } } if (!flag) { groupName.add(musicList.get(i).getArtist()); List<MusicInfo> musicListWithSameSinger2 = new ArrayList<MusicInfo>(); musicListWithSameSinger2.add(musicList.get(i)); musicGroupBySinger.add(musicListWithSameSinger2); } } } @Override public int getGroupCount() { return musicGroupBySinger.size(); } @Override public int getChildrenCount(int groupPosition) { return musicGroupBySinger.get(groupPosition).size(); } @Override public Object getGroup(int groupPosition) { return musicGroupBySinger.get(groupPosition); } @Override public Object getChild(int groupPosition, int childPosition) { return musicGroupBySinger.get(groupPosition).get(childPosition); } @Override public long getGroupId(int groupPosition) { return 0; } @Override public long getChildId(int groupPosition, int childPosition) { return 0; } //true还是false感觉没什么区别 @Override public boolean hasStableIds() { return false; } //获取Group的视图 @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { if (convertView == null) { LayoutInflater inflater = LayoutInflater.from(context); // R.layout.groups这个参数是group的视图 convertView = inflater.inflate(R.layout.groups, null); } TextView title = (TextView) convertView.findViewById(R.id.tvSinger); title.setText(groupName.get(groupPosition));// 设置大组成员名称 return convertView; } //获取展开的子视图 /** * 在这里我有必要提一下listview加载视图的优化问题 * <p/> * 一、复用convertView * 首先讲下ListView的原理:ListView中的每一个Item显示都需要Adapter调用一次getView的方法,这个方法会传入一个convertView的参数, * 返回的View就是这个Item显示的View。如果当Item的数量足够大,再为每一个Item都创建一个View对象,必将占用很多内存, * 创建View对象(mInflater.inflate(R.layout.lv_item, null);从xml中生成View,这是属于IO操作)也是耗时操作,所以必将影响性能。 * Android提供了一个叫做Recycler(反复循环器)的构件,就是当ListView的Item从上方滚出屏幕视角之外,对应Item的View会被缓存到Recycler中, * 相应的会从下方生成一个Item,而此时调用的getView中的convertView参数就是滚出屏幕的Item的View,所以说如果能重用这个convertView, * 就会大大改善性能。 * 所以getChildView 一开始会有一个判断语句 * if (convertView == null) 如果不为空就直接使用之前那个。 * <p/> * <p/> * 二、使用viewHolder类 * 我们都知道在getView方法中的操作是这样的: * 先从xml中创建view对象(inflate操作,我们采用了重用convertView方法优化),然后在这个view去findViewById, * 找到每一个子View,如:一个TextView等。这里的findViewById操作是一个树查找过程,也是一个耗时的操作,所以这里也需要优化, * 就是使用viewHolder,把每一个子View都放在Holder中,当第一次创建convertView对象时,把这些子view找出来。 * 然后用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。 * 当第二次重用convertView时,只需从convertView中getTag取出来就可以。 */ @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { int position = musicList.indexOf(getChild(groupPosition, childPosition)); // 优化listView ViewHolder viewHolder; if (convertView == null) { // R.layout.music_item是每一项的视图xml文件 convertView = LayoutInflater.from(MainActivity.this).inflate( R.layout.music_item, null); TextView pTitle = (TextView) convertView .findViewById(R.id.title); viewHolder = new ViewHolder(pTitle); // 用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。 convertView.setTag(viewHolder); } else { // 当第二次重用convertView时,只需从convertView中getTag取出来就可以。 viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.title.setText(musicList.get(position).getTitle()); return convertView; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return false; } } class ViewHolder { TextView title; public ViewHolder(TextView pTitle) { title = pTitle; } } }
成果展示:
相关推荐
在Android开发中,`ExpandableListView`...同时,对于代码优化,可以考虑改进数据结构,减少内存占用,提高UI响应速度,以及对不同设备的适配等。这是一个综合性的Android开发练习,对提升实际项目开发能力非常有帮助。
- **异步加载**:对于大数据量的列表,可以考虑使用异步加载策略,只在需要时加载特定Group的Child,减少内存占用。 5. **常见问题** - **点击事件冲突**:在处理点击事件时,可能会遇到Group与Child的点击事件...
此外,还可以根据需要加载和隐藏子条目,以减少内存占用。 8. **交互效果**: 可以通过设置动画效果,如展开和折叠的过渡动画,提升用户体验。`ExpandableListView`提供了`setGroupIndicator()`方法来设置展开/...
2. 数据加载策略:对于大数据量的列表,可以考虑使用懒加载或者分页加载,以减少内存占用和提高加载速度。 3. 刷新策略:当数据源改变时,使用`notifyDataSetChanged()`或`notifyGroupChanged()`、`...
同时,为了减少内存占用,可以使用ProGuard工具对代码进行混淆和优化。 现在,让我们看看具体的实现步骤: 1. 创建数据模型类,如`Group`表示父级,`Child`表示子级。每个`Group`包含一个`List<Child>`。 2. 创建...
- 使用懒加载策略,只在需要时加载子项,减少初始加载时的内存占用。 - 避免一次性加载所有数据,特别是在数据量大的情况下,可以采用分页加载策略。 - 利用View Holder模式提高列表滚动性能。 5. **自定义样式*...
- 对于大量的数据,考虑使用分页加载或懒加载策略,减少内存占用。 ### 注意事项 - 确保在适配器中正确地更新数据,以便反映数据源的变化。 - 避免在主线程中执行耗时操作,如数据加载或计算,以防止应用卡顿。 ...
下面将详细介绍这个主题,并围绕`ExpandableListView`的使用、动态添加与删除操作以及相关的最佳实践展开讨论。 首先,我们需要理解`ExpandableListView`的基本结构。它由两个层次组成:组(Group)和子项(Child)...
只有当群组展开时,才加载并显示对应的子项,这样可以减少内存占用和渲染时间。 7. **布局文件**:最后,你需要在XML布局文件中添加`ExpandableListView`,并设置适配器。同时,群组和子项的视图也需要单独定义,...
这涉及到对`View`类的扩展,重写`onTouchEvent`方法,以及使用`Animator`或`Transition`来添加动画效果,提升用户体验。 此外,Android的`ViewStub`也可以用于实现简单的折叠效果。`ViewStub`是一个轻量级的视图,...
6. **性能优化**:对于大型的树结构,可能需要采用虚拟化技术,只渲染可视区域的节点,减少内存占用和渲染时间。 在实际应用中,这种控件可以帮助用户快速定位目标,特别是在处理大量分层信息时,大大提高了交互...
这可能涉及虚拟化技术,只渲染当前可视区域的列表项,减少内存占用和渲染开销。 综上所述,"仿QQ多级列表框实现"涵盖了数据结构设计、用户界面开发、事件处理、数据加载策略、数据绑定和界面定制等多个方面,是一个...
这种方式既保证了数据的高效检索,又降低了内存占用。 安全方面,K-9 Mail提供了SSL/TLS加密选项,确保邮件传输过程的安全。源代码中的SocketFactory和SSLContext配置,展示了如何实现安全连接。同时,它还支持PGP...
这有助于降低启动时的内存占用,提高用户体验。 10. **适配器的更新**: 当数据源发生变化时,如添加、删除或修改数据,Adapter需要提供相应的通知方法(如notifyDataSetChanged())来更新ListView的显示。 综上所...
- 考虑到描述中提到的作者是新人,可能代码实现较为简单,实际项目中需要考虑性能优化,例如使用ViewHolder模式减少视图查找,避免内存泄漏,以及在数据加载时使用异步加载机制,提高用户体验。 6. **资源管理**:...