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

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


 成果展示:



 

猜你喜欢

转载自2723364262.iteye.com/blog/2263459