上篇博客讲到如何获取手机中所有歌曲的信息。本文就把上篇获取到的歌曲按照歌手名字分类。用一个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; } } }
成果展示: