您的位置:首页 > 其它

使用ExpandableListView以及如何优化view的显示减少内存占用

2016-11-18 20:35 573 查看
上篇博客讲到如何获取手机中所有歌曲的信息。本文就把上篇获取到的歌曲按照歌手名字分类。用一个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;
}
}
}

 成果展示:

 

 

 



 

 

 





大小: 64.4 KB
查看图片附件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐