`

使用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;
        }
    }
}


 成果展示:

 

 

 



 

 

 

  • 大小: 64.4 KB
分享到:
评论

相关推荐

    ExpandableListView 实现QQ好友动态与评价

    在Android开发中,`ExpandableListView`...同时,对于代码优化,可以考虑改进数据结构,减少内存占用,提高UI响应速度,以及对不同设备的适配等。这是一个综合性的Android开发练习,对提升实际项目开发能力非常有帮助。

    ExpandableListview

    - **异步加载**:对于大数据量的列表,可以考虑使用异步加载策略,只在需要时加载特定Group的Child,减少内存占用。 5. **常见问题** - **点击事件冲突**:在处理点击事件时,可能会遇到Group与Child的点击事件...

    Android-基于ExpandableListView实现评论和回复的功能

    此外,还可以根据需要加载和隐藏子条目,以减少内存占用。 8. **交互效果**: 可以通过设置动画效果,如展开和折叠的过渡动画,提升用户体验。`ExpandableListView`提供了`setGroupIndicator()`方法来设置展开/...

    基于自定义适配器的ExpandableListView

    2. 数据加载策略:对于大数据量的列表,可以考虑使用懒加载或者分页加载,以减少内存占用和提高加载速度。 3. 刷新策略:当数据源改变时,使用`notifyDataSetChanged()`或`notifyGroupChanged()`、`...

    ExpandableListView仿QQ列表,上下可刷新

    同时,为了减少内存占用,可以使用ProGuard工具对代码进行混淆和优化。 现在,让我们看看具体的实现步骤: 1. 创建数据模型类,如`Group`表示父级,`Child`表示子级。每个`Group`包含一个`List&lt;Child&gt;`。 2. 创建...

    expandabLelist.zip

    - 使用懒加载策略,只在需要时加载子项,减少初始加载时的内存占用。 - 避免一次性加载所有数据,特别是在数据量大的情况下,可以采用分页加载策略。 - 利用View Holder模式提高列表滚动性能。 5. **自定义样式*...

    ExpandeList

    - 对于大量的数据,考虑使用分页加载或懒加载策略,减少内存占用。 ### 注意事项 - 确保在适配器中正确地更新数据,以便反映数据源的变化。 - 避免在主线程中执行耗时操作,如数据加载或计算,以防止应用卡顿。 ...

    ExpanLVOperation

    下面将详细介绍这个主题,并围绕`ExpandableListView`的使用、动态添加与删除操作以及相关的最佳实践展开讨论。 首先,我们需要理解`ExpandableListView`的基本结构。它由两个层次组成:组(Group)和子项(Child)...

    二级Android可展开的列表(带展开动画的expandlistview)

    只有当群组展开时,才加载并显示对应的子项,这样可以减少内存占用和渲染时间。 7. **布局文件**:最后,你需要在XML布局文件中添加`ExpandableListView`,并设置适配器。同时,群组和子项的视图也需要单独定义,...

    搞了个折叠的试图

    这涉及到对`View`类的扩展,重写`onTouchEvent`方法,以及使用`Animator`或`Transition`来添加动画效果,提升用户体验。 此外,Android的`ViewStub`也可以用于实现简单的折叠效果。`ViewStub`是一个轻量级的视图,...

    能显示树状目录的组合框

    6. **性能优化**:对于大型的树结构,可能需要采用虚拟化技术,只渲染可视区域的节点,减少内存占用和渲染时间。 在实际应用中,这种控件可以帮助用户快速定位目标,特别是在处理大量分层信息时,大大提高了交互...

    仿QQ多级列表框实现

    这可能涉及虚拟化技术,只渲染当前可视区域的列表项,减少内存占用和渲染开销。 综上所述,"仿QQ多级列表框实现"涵盖了数据结构设计、用户界面开发、事件处理、数据加载策略、数据绑定和界面定制等多个方面,是一个...

    android邮件程序源代码k9mail

    这种方式既保证了数据的高效检索,又降低了内存占用。 安全方面,K-9 Mail提供了SSL/TLS加密选项,确保邮件传输过程的安全。源代码中的SocketFactory和SSLContext配置,展示了如何实现安全连接。同时,它还支持PGP...

    安卓Android源码——ListView多级展示,item由对象Leaf提供数据,可设置多个控件.zip

    这有助于降低启动时的内存占用,提高用户体验。 10. **适配器的更新**: 当数据源发生变化时,如添加、删除或修改数据,Adapter需要提供相应的通知方法(如notifyDataSetChanged())来更新ListView的显示。 综上所...

    listview下拉刷新加载更多

    - 考虑到描述中提到的作者是新人,可能代码实现较为简单,实际项目中需要考虑性能优化,例如使用ViewHolder模式减少视图查找,避免内存泄漏,以及在数据加载时使用异步加载机制,提高用户体验。 6. **资源管理**:...

Global site tag (gtag.js) - Google Analytics