Android ListView的优化

这次复习一下ListView的优化,大概分三种方法:
  1.view item重用机制(如果Adapter的getView(int position, View convertView, ViewGroup parent),当convertView==null时才会通过findViewById()或者Inflate在xml中实例化,否则直接拿来用)
  2.viewHolder缓存item(不必每次都通过findViewById()或者Inflate在xml中查找或实例化,而是每次实例化后都存在viewHolder这个内部类中(放在内存中),大大加快了加载的速度。但不足很明显,数据量过大时会造成内存溢出,应用崩溃。)
  3.分批加载item,甚至有更好的分页式加载(分页查询在学校做java后台时也有过使用,通过当前页数index,计算出当前要加载的数据list,最终显示在jsp页面上。而分页的好处也很明显:每次只需要获取和加载一页个数的数据,流量小,客户体验好!)。
  下面通过代码来进行解释:
  

public class VideoActivity extends Activity implements AbsListView.OnScrollListener{
...
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initView();
        initData();
        Log.i("XX", "从心开始了");
    }
    /**
    * 初始化界面
    **/
    private void initView() {
        setContentView(R.layout.activity_video);
        videoList = (ListView) findViewById(R.id.video_list);
    }

    private void initData() {
        adapter = new MyAdapter(this.getApplicationContext());
        videoList.setAdapter(adapter);
        videoList.setOnScrollListener(this);
        path = new ArrayList<>();
        path.add("视频地址");//可以是网络地址
        path.add("视频地址");
        path.add("视频地址");
        path.add("视频地址");
        path.add("视频地址");
        path.add("视频地址");
        path.add("视频地址");
        path.add("视频地址");
        path.add("视频地址");
        adapter.setData(path);
    }

    /**
     * Callback method to be invoked while the list view or grid view is being scrolled. 
     * If the view is being scrolled, this method will be called before the next frame of the scroll is rendered. 
     * In particular, it will be called before any calls to Adapter.getView(int, View, ViewGroup).
     */
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    @Override
    /**
     * Callback method to be invoked when the list or grid has been scrolled.
     *  This will be called after the scroll has completed
     */
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        Log.i("onScroll", "当前" + currentPosition);
        Log.i("onScroll", "可见的第一个" + videoList.getFirstVisiblePosition());
        if ((currentPosition < videoList.getFirstVisiblePosition() || currentPosition > videoList
                .getLastVisiblePosition()) && isPlaying && getResources().getConfiguration().orientation
                == Configuration.ORIENTATION_PORTRAIT) {
            closeVideo();
        }
    }

  private class MyAdapter extends BaseAdapter {

        private Context mContext;

        private List<String> videoPaths;

        public MyAdapter(Context mContext) {
            this.mContext = mContext;
        }

        public void setData(List<String> videoPaths) {
            this.videoPaths = videoPaths;
            notifyDataSetChanged();
        }

        @Override
        public int getCount() {
            return videoPaths != null && videoPaths.size() > 0 ? videoPaths.size() : 0;
        }

        @Override
        public Object getItem(int position) {
            return videoPaths != null && videoPaths.size() > 0 ? videoPaths.get(position) : null;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            //使用holder这一做法,便于当itemView中的布局复杂时容易阅读理解和管理
            ViewHolder viewHolder = null;
            //重用itemView,而不是重新Inflate①
            if (convertView == null) {
                convertView = LayoutInflater.from(mContext).inflate(R.layout.video_play_items, parent, false);
                viewHolder = new ViewHolder();
                viewHolder.play_btn = (ImageView) convertView.findViewById(R.id.play_btn);
                viewHolder.show_layout = (FrameLayout) convertView.findViewById(R.id.show_layout);
                viewHolder.play_view = (VideoPlayView) convertView.findViewById(R.id.video_play_view);
                //将生成的holder与对应的item“绑定”,省去了重新Inflate到加载进内存的过程。效率很高。
                convertView.setTag(viewHolder);
            } else {
                //重用itemView,而不是重新Inflate②,
                viewHolder = (ViewHolder) convertView.getTag();
            }

            viewHolder.play_btn.setOnClickListener(new MyClick(position,
                    viewHolder.play_view, viewHolder.show_layout, convertView));

            if (currentPosition == position) {
                viewHolder.play_view.setVisibility(View.VISIBLE);
            } else {
                viewHolder.play_view.setVisibility(View.GONE);
                viewHolder.show_layout.setVisibility(View.VISIBLE);
                viewHolder.play_view.stop();
            }
            return convertView;
        }
        //Holder用于存放当前的ItemView布局,方便管理和阅读
        private  class ViewHolder {
            private ImageView play_btn;//播放按钮
            private FrameLayout show_layout;
            private VideoPlayView play_view;

        }

        class MyClick implements View.OnClickListener {
            private int position;
            private VideoPlayView playView;
            private FrameLayout show_layout;
            private View convertView;

            public MyClick(int position, VideoPlayView playView, FrameLayout show_layout, View convertView) {
                this.position = position;
                this.show_layout = show_layout;
                this.playView = playView;
                this.convertView = convertView;
            }

            @Override
            public void onClick(View v) {
                isPlaying = true;
                currentPosition = position;
                show_layout.setVisibility(View.GONE);
                playView.setUrl(videoPaths.get(position));
                currentItemView = convertView;
                setPlayView(playView);
                playView.openVideo();
                notifyDataSetChanged();
            }
        }
    }
    ...
}

  根据以上代码,其实可以看到关于ListView优化的前两种方法,而第三种方法的代码正在利用闲时间编写,之后再会写一篇关于完整的ListView优化的代码和解释。
  最后,这里只提一下第三种方法的实现思路,添加一个当前页的全局变量,在Adapter类中加载当前页要显示的data,onScroll实现中设置好一页显示的item的最大个数(要根据屏幕高度与每个item的高度进行计算,向上取整),当滑动到最后一个后仍向下滑动,那么获取和加载下一页的数据到Adapter中。
  而分页式的数据加载适合于大数据的在线传输和显示,既可以降低服务器的压力,也使得客户端能够非常流畅。
下图是实现好的效果:

  这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值