zoukankan      html  css  js  c++  java
  • App优化(一)通用ViewHolder

    App优化(一)通用ViewHolder

    一直都是用歇菜方式写的Adapter,这种方式每次加载view,都要建立很多view对象,如果超过一定数量这种加载方式肯定要歇菜。在应用上架后,修正了用户提交的Bug后,我打算系统的对App做优化。第一步就是优化Adapter,那么就从ViewHolder开始。

    优化目标

    不光是要让效率变高,代码也要好看,而且要增加可重用性,为以后的开发打好基础。下面是我的目标:

    • 让代码变得更加效率
    • 让代码好看一些
    • 为以后的App开发速度做下良好的知识储备

    知识

    很幸运我直接就搜到了hyman老师的视频。

    创建一个ViewHolder

    在ViewHolder里,用SparseArray来存储一个View,我们首先来定义变量

    private SparseArray<View> mViews;
    private int mPosition;
    private View mConvertView;
    

    然后我们在定义一个静态方法get()来返回这个ViewHolder

    public static ViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {
        if(convertView == null) {
            return new ViewHolder(context,parent,layoutId,position);
        } else {
            ViewHolder holder = (ViewHolder)convertView.getTag();
            holder.mPosition = position;
            return holder;
        }
    }
    

    在这个方法里在 converView == null 的时候我们才创建一个ViewHolder。构造函数为

    public ViewHolder(Context context, ViewGroup parent, int layoutId, int position) {
        this.mPosition = position;
        this.mViews = new SparseArray<View>();
        mConvertView = LayoutInflater.from(context).inflate(layoutId,parent,false);
        mConvertView.setTag(this);
    }
    

    使用 convertView.getTag()convertView.setTag() 来关联ViewHolder之后,在来改变ViewHolder都是可以的,前提是先要关联。

    然后我们需要一个方法来加入和读取控件。这个方法用一个泛型来实现的

    /***
     * 通过viewId返回View
     * @param viewId
     * @param <T>
     * @return
     */
    public <T extends View> T getView(int viewId) {
        View view = mViews.get(viewId);
        if(view == null) {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId,view);
        }
        return (T)view;
    }
    

    在这个方法里通过空间id来获得控件,如果没有就从convertView里面找出来。还有一个方法是返回这个convertView

    public View getConvertView() {
        return mConvertView;
    }
    

    初步使用这个ViewHolder

    我创建了一个Adapter类为 RiftExAdapter 扩展至 BaseAdapter,在没有使用ViewHolder以前代码大概是这个样子的

       public View getView(int position, View convertView, ViewGroup parent) {
            RiftInfo bean = mDatas.get(position);
            if(null == convertView) {
                convertView = ((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
                        .inflate(R.layout.item_rift, null);
            }
            TextView rankRift = (TextView)convertView.findViewById(R.id.rankRift);
            TextView battletagRift = (TextView) convertView.findViewById(R.id.battletagRift);
            TextView riftLevelRift = (TextView) convertView.findViewById(R.id.riftLevelRift);
            TextView riftTimeRift = (TextView) convertView.findViewById(R.id.riftTimeRift);
            rankRift.setText(bean.getRank());
            battletagRift.setText(bean.getBattleTag());
            riftLevelRift.setText(bean.getRiftLevel());
            riftTimeRift.setText(bean.getRiftTime());
            return null;
        }
    

    首先加入ViewHolder后代码初步修改为这个样子

    public View getView(int position, View convertView, ViewGroup parent) {
        RiftInfo bean = mDatas.get(position);
        ViewHolder holder = ViewHolder.get(mContext, convertView, parent, R.layout.item_rift, position);
        ((TextView)holder.getView(R.id.rankRift)).setText(bean.getRank());
        ((TextView)holder.getView(R.id.battletagRift)).setText(bean.getBattleTag());
        ((TextView)holder.getView(R.id.riftLevelRift)).setText(bean.getRiftLevel());
        ((TextView)holder.getView(R.id.riftTimeRift)).setText(bean.getRiftTime());       
        return holder.getConvertView();
    }
    

    运行一下看看结果

    (如图1.1)

    初步使用小结

    以后使用ViewHolder只需要3步

    1. 使用get()方法得到holder
    2. 使用getView()来得到空间
    3. 返回一个holder.getConvertView()

    可以节省大量的代码,尤其是ListView多了之后。

    稍微复杂一点的情况

    实际的App界面中还涉及到一个图片。当然如果是资源id的图片那跟直接使用setText是没有区别的。如果使用的是网络图片的话,我使用了
    com.android.volley.toolbox.ImageLoader;

    那么首先要申明一个变量

    ImageLoader mImageLoader;

    然后在getView() 中是这样使用的

    if (position > 0) {
            mImageLoader = MySingleton.getInstance(mContext).getImageLoader();
            mImageLoader.get(bean.getSrc(), ImageLoader.getImageListener((ImageView)holder.getView(R.id.battletagImageRift),
                    R.drawable.def_image, R.drawable.err_image));
        }
    

    在这里我使用了Volley的ImageLoader给一个ImageView异步读取了一个网络图片。

    MySingleton是官方提供的一个管理Volley队列的类。

    小结

    封装后的ViewHolder并不影响正常的使用。

  • 相关阅读:
    剑指offer-二维数组中的查找
    TF-IDF(term frequency–inverse document frequency)
    Java实现中文字符串的排序功能
    当前课程
    【R】资源整理
    CentOS相关
    【转】Setting up SDL Extension Libraries on MinGW
    【转】Setting up SDL Extension Libraries on Visual Studio 2010 Ultimate
    【转】Setting up SDL Extension Libraries on Code::Blocks 12.11
    【转】Setting up SDL Extension Libraries on Visual Studio 2019 Community
  • 原文地址:https://www.cnblogs.com/canglin/p/4575246.html
Copyright © 2011-2022 走看看