zoukankan      html  css  js  c++  java
  • Android高手进阶——Adapter深入理解与优化

    Android高手进阶——Adapter深入理解与优化


        通常是针对包括多个元素的View,如ListViewGridViewExpandableListview,的时候我们是给其设置一个AdapterAdapter是与View之间提供数据的桥梁,也是提供每一个Item的视图桥梁。

     

    ListView为例。其工作原理为:

    ListView针对List中每一个item adapter都会调用一个getView的方法获得布局视图

    我们通常会Inflate一个新的View,填充数据并返回显示

     

        当然假设我们的Item非常多话(比方上万个),都会新建一个View吗?非常明显这样内存是接受不了的,Google也不会这么做。Android中有个叫做Recycler的构件,下图是他的工作原理:

     

        非常明显,不管数据中是多少个item。在显示上Recycler仅仅存储当中可见的View在内存中。

    当向下滑动时。顶部不可见Item直接回移动到下方再次填充数据变为新增项。

    这样就不用每次都新建一个View了。

    这个也就是我们在Adapter中常见的getView方法的调用,相应此方法我们就能看出,convertView就是每一Item在Recyler之前的布局视图。

     

    public View getView(int position, View convertView, ViewGroupparent)


     

    所以。Android已经给我们提供了Recycler机制了,我们就应该利用此机制,而不是每次都去inflate一个View

    Example

    Don’t

    public View getView(int position, View convertView, ViewGroupparent){
        convertView = LayoutInflater.from(mContext).inflate(R.layout.item_view,null);
        //dosomething…
        return converView;
    }
    


    
    

     

    Do

    public View getView(int position, View convertView, ViewGroupparent){
         if (convertView ==null) {
               convertView =LayoutInflater.from(mContext).inflate(R.layout.item_view, null);
         }
        //dosomething…
        return converView;
    }


     

     

    ViewHolder的作用

             之前所说的Recycler模式是为了解决反复inflate时候造成的View资源浪费,还哪有什么方法何可再次优化我们的性能吗?答案是Yes。

             我们还是从getView中的每个方法调用去查看,发现事实上我们拿到convertView的时候,每次都会依据这个布局去findViewById。例如以下,使我们通常的写法:

     

    if (convertView == null) {              
       convertView = mInflater.inflate(R.layout.item_view, null);          
    } 
    TextView titleTextView = (TextView) convertView.findViewById(R.id.text));         
    ImageView iconImageView = (ImageView)convertView.findViewButId( R.id.icon)); 
    //DoSomething…




            

             findViewById是在解析layout.xml布局那种当中的子View,解析xml是一个力气活,所以Google也建议我们将这个费力不讨好的活优化起来,所以提出了ViewHolder的概念。

           即,使用一个静态类,保存xml中的各个子View的引用关系。这样就不必要每次都去解析xml了。例如以下:就是针对上面代码写的一个ViewHolder


    static class ViewHolder { 
        TextView titleTextView;  
        ImageView iconImageView; 
    } 



     

    可是。在getView方法中我们仅仅能拿到三个參数,positionconvertViewviewGroup是拿不到我们自己定义的ViewHolder的。所以。我们希望通过convertView拿到ViewHolder仅仅能将其放在tag里。

    以下是一个完整的ViewHolder使用exmaple:

     

     

        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if (convertView == null) {
                convertView = mInflater.inflate(R.layout.item_view, null);
                holder = new ViewHolder();
                holder.titleTextView = (TextView) convertView.findViewById(R.id.text);
                holder.iconImageView = (ImageView) convertView.findViewById(R.id.icon);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            holder.titleTextView.setText(DATA[pos].title);
            holder.iconImageView.setImageBitmap(DATA[pos].bitmap);
            return convertView;
        }
    
        static class ViewHolder {
            TextView titleTextView;
            ImageView iconImageView;
        }

     

    Tips. Support.v7中的RecyclerView 就是採用了此思想来制作的。

    多个类型的ViewType

             当我们在Adapter中调用方法getView的时候,假设整个列表中的Item View假设有多种类型布局,如:


     

             我们继续使用convertView来将数据从新填充貌似不可行了。由于每次返回的convertView类型都不一样。无法重用。

             Android在设计上的时候。也想到了这点。

    所以,在adapter中预留的两个方法。

            

    public int getItemViewType(int position) ;


     

    public int getViewTypeCount();

     

    仅仅须要又一次这两个方法。设置一下ItemViewType的个数和推断方法。Recycler就能有选择性的给出不同的convertView了。

            

             Example:

     

        @Override
        public intgetItemViewType(int position) {
            if (DATA[pos].type == 0) {
                return 0;
            } else {
                return 1;
            }
        }
    
        @Override
        public int getViewTypeCount() {
            return 2;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup arg2) {
            TitleViewHolder titleHolder;
            InfoViewHolder infoHolder;
            int type = getItemViewType(position);
    
            if (convertView == null) {
                switch (type) {
                case 0:
                    convertView = mInflater.inflate(R.layout.item_view, null);
                    titleHolder = new TitleViewHolder();
                    titleHolder.titleTextView = (TextView) convertView.findViewById(R.id.text);
                    titleHolder.iconImageView = (ImageView) convertView.findViewById(R.id.icon);
                    convertView.setTag(titleHolder);
                    break;
                case 1:
                    convertView = mInflater.inflate(R.layout.item_view2, null);
                    infoHolder = new InfoViewHolder();
                    infoHolder.titleTextView = (TextView) convertView.findViewById(R.id.text);
                    convertView.setTag(infoHolder);
                    break;
                }
            } else {
                switch (type) {
                case 0:
                    titleHolder = (TitleViewHolder) convertView.getTag();
                    break;
                case 1:
                    infoHolder = (InfoViewHolder) convertView.getTag();
                    break;
                }
            }
            switch (type) {
            case 0:
                titleHolder.titleTextView.setText(DATA[pos].title);
                break;
            case 1:
                infoHolder.titleTextView.setText(DATA[pos].title);
                infoHolder.iconImageView.setImageBitmap(DATA[pos].bitmap);
                break;
            }
    
            return convertView;
        }
    
        static class TitleViewHolder {
            public ImageView iconImageView;
            public TextView titleTextView;
        }
    
        static class InfoViewHolder {
            TextView titleTextView;
            ImageView iconImageView;
        }


     

    NotifyDataSetChanged刷新机制

             当ListView中的数据发生了改变。我们希望刷新ListView中的View时,我们通常会调用NotifyDataSetChanged来刷新ListView。

    看一下它的源代码:


        public void notifyChanged() {
            synchronized (mObservers) {
                // 向每个子View发送onChanged
                for (int i = mObservers.size() - 1; i >= 0; i--) {
                    mObservers.get(i).onChanged();
                }
            }
        }



    发现它针对每个子View都做了刷新,当然,假设我们的数据都变量还能够理解。可是。一般条件下,我们须要更新的View不多。

    频繁的调用NotifyDataSetChanged方法。刷新整个界面不合适。这样会把界面上显示的所有item都所有重绘一次,即使仅仅有一个view的内容发生了变化。

             所以。我们能够写一个update的方法,来单独刷新一个View

    private void updateView(int itemIndex){
        intvisiblePosition = yourListView.getFirstVisiblePosition();
        Viewv = yourListView.getChildAt(itemIndex - visiblePosition);
             ViewHolder viewHolder =(ViewHolder)v.getTag();
             if(viewHolder!= null){
                   viewHolder.titleTextView.setText("我更新了");
             }   
    }


     

    Adapter中的网络图片优化

             ListView中的每一项Item基本都会带着网络图片。当item比較多的时候,过多的网络请求和过多的图片存储都会是ListView变慢变卡。


    所以针对其做一下优化:

        

        ●  採用线程池进行网络图片请求,网络图片请求获取后使用本地缓存处理(LRUCache)。内存+本地文件缓存。当然,为了防止内存溢出与回收不及时,须要使用弱引用(WeakReference)来存储内存中的图片。

         

        ●  对网络中取到的图片进行按比例缩放。以降低内存消耗。

        

        ●  滑动的时候不须要对网络图片进行请求。

    由于,网络请求一般比較耗时。某Item的图片,在请求来的时候假设被Recycler换掉。图片就会相应不上该Item。

     

           

         Tips.网络请求的工具类比較多不方便举样例。可是使用比較频繁的网络图片请求工具类就是Volley了,Volley提供了一个ImageLoader的工具类和NetworkImageView的网络图片请求View




    /**
     * @author zhoushengtao(周圣韬)
     * @since 2014年7月8日 下午15:08:29
     * @weixin stchou_zst 

     * @blog http://blog.csdn.net/yzzst
     */


  • 相关阅读:
    Hard Rock
    Codeforces Round #416 (Div. 2) B. Vladik and Complicated Book
    codeforces 793B. Igor and his way to work
    codeforces 1B Spreadsheets
    HDU 1069 Monkey and Banana
    codeforces 2B The least round way
    【机器学习】 通俗说拟合
    python-八皇后问题
    python-核心知识思维导图
    python-@property 属性
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5180453.html
Copyright © 2011-2022 走看看