BaseAdapter应用分析及异步加载

今天给大家分享一些BaseAdapter的使用及原理(直接照搬的某位博主的小编认为写得比较好的文章),以及小编用BaseAdapter时Item异步加载的实现方式。

     前言     

  话说开发用了各种Adapter之后感觉用的最舒服的还是BaseAdapter,尽管使用起来比其他适配器有些麻烦,但是使用它却能实现很多自己喜欢的列表布局,比如ListView、GridView、Gallery、Spinner等等。它是直接继承自接口类Adapter的,使用BaseAdapter时需要重写很多方法,其中最重要的当属getView,因为这会涉及到ListView优化等问题,其他的方法可以参考链接的文章

BaseAdapter与其他Adapter有些不一样,其他的Adapter可以直接在其构造方法中进行数据的设置,比如

SimpleAdapter adapter = new SimpleAdapter(this, getData(), R.layout.list_item, new String[]{"img","title","info",new int[]{R.id.img, R.id.title, R.id.info}});

但是在BaseAdapter中需要实现一个继承自BaseAdapter的类,并且重写里面的很多方法,例如

复制代码
class MyAdapter extends BaseAdapter

    {

        private Context context;

        public MyAdapter(Context context)

        {

            this.context = context;

        }

        @Override

        public int getCount() {

            // How many items are in the data set represented by this Adapter.(在此适配器中所代表的数据集中的条目数)
            return 0;

        }



        @Override

        public Object getItem(int position) {

            // Get the data item associated with the specified position in the data set.(获取数据集中与指定索引对应的数据项)
            return null;

        }



        @Override

        public long getItemId(int position) {

            // Get the row id associated with the specified position in the list.(取在列表中与指定索引对应的行id)
            return 0;

        }



        @Override

        public View getView(int position, View convertView, ViewGroup parent) {

            // Get a View that displays the data at the specified position in the data set.
            return null;

        }

        

    }
复制代码

这里面没什么难度,但是这个getView方法必须好好处理,也是最麻烦的

第一种:没有任何处理,不建议这样写。如果数据量少看将就,但是如果列表项数据量很大的时候,会每次都重新创建View,设置资源,严重影响性能,所以从一开始就不要用这种方式

复制代码
        @Override

        public View getView(int position, View convertView, ViewGroup parent) {

            View item = mInflater.inflate(R.layout.list_item, null);

            ImageView img = (ImageView)item.findViewById(R.id.img) 

            TextView title = (TextView)item.findViewById(R.id.title);

            TextView info = (TextView)item.findViewById(R.id.info);

            img.setImageResource(R.drawable.ic_launcher);

            title.setText("Hello");

            info.setText("world");

            

            return item;

        }
复制代码

第二种ListView优化:通过缓存convertView,这种利用缓存contentView的方式可以判断如果缓存中不存在View才创建View,如果已经存在可以利用缓存中的View,提升了性能

复制代码
        public View getView(int position, View convertView, ViewGroup parent) {

            if(convertView == null)

            {

                convertView = mInflater.inflate(R.layout.list_item, null);

            }

            

            ImageView img = (ImageView)convertView.findViewById(R.id.img) 

            TextView title = (TextView)convertView.findViewById(R.id.title);

            TextView info = (TextView)ConvertView.findViewById(R.id.info);

            img.setImageResource(R.drawable.ic_launcher);

            title.setText("Hello");

            info.setText("world");

            

            return convertView;

        }
复制代码

第三种ListView优化:通过convertView+ViewHolder来实现,ViewHolder就是一个静态类,使用ViewHolder 的关键好处是缓存了显示数据的视图(View),加快了 UI 的响应速度。

当我们判断 convertView == null  的时候,如果为空,就会根据设计好的List的Item布局(XML),来为convertView赋值,并生成一个viewHolder来绑定converView里面的各个View控件(XML布局里面的那些控件)。再用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。(看下面代码中)

如果convertView不为空的时候,就会直接用convertView的getTag(),来获得一个ViewHolder。

复制代码
    //在外面先定义,ViewHolder静态类
    static class ViewHolder

    {

        public ImageView img;

        public TextView title;

        public TextView info;

    }

//然后重写getView
        @Override

        public View getView(int position, View convertView, ViewGroup parent) {

            ViewHolder holder;

            if(convertView == null)

            {

                holder = new ViewHolder();

                convertView = mInflater.inflate(R.layout.list_item, null);

                holder.img = (ImageView)item.findViewById(R.id.img) 

                holder.title = (TextView)item.findViewById(R.id.title);

                holder.info = (TextView)item.findViewById(R.id.info);

                convertView.setTag(holder);

            }else

            {

                holder = (ViewHolder)convertView.getTag();

                holder.img.setImageResource(R.drawable.ic_launcher);

                holder.title.setText("Hello");

                holder.info.setText("World");

            }

            

            return convertView;

        }
复制代码

到这里,可能会有人问ViewHolder静态类结合缓存convertView与直接使用convertView有什么区别吗,是否重复了

在这里,官方给出了解释

提升Adapter的两种方法

To work efficiently theadapter implemented here uses two techniques:
-It reuses the convertView passed to getView() to avoid inflatingView when it is not necessary

(译:重用缓存convertView传递给getView()方法来避免填充不必要的视图)
-It uses the ViewHolder pattern to avoid calling findViewById()when it is not necessary

(译:使用ViewHolder模式来避免没有必要的调用findViewById():因为太多的findViewById也会影响性能)
ViewHolder类的作用
-The ViewHolder pattern consists in storing a data structure in thetag of the view
returned by getView().This data structures contains references tothe views we want to bind data to,
thus avoiding calling to findViewById() every time getView() isinvoked

(译:ViewHolder模式通过getView()方法返回的视图的标签(Tag)中存储一个数据结构,这个数据结构包含了指向我们

要绑定数据的视图的引用,从而避免每次调用getView()的时候调用findViewById())

====================================================================
通过以上介绍,相信不少新手老爷们都已经对getView()方法有了实质性的了解,以后用起来也就可以任己发挥,不会因为只能对照别人的代码写而有所束缚了。
下面小编就分享一下自己在GridView使用Adapter的过程中设计的异步加载的实现。废话不多说,直接上代码:

public class FavoriteAlbumAdapter extends BaseAdapter {

    private ListmAlbumList;
    privateContext mContext;
    privateGridView mGridView;
    privateViewHolder mViewHolder;
   
    publicFavoriteAlbumAdapter(Context context, List list, GridView gridView){
       mContext =context;
       mAlbumList =list;
       mGridView =gridView;
    }
   
   @Override
    public intgetCount() {
       // TODOAuto-generated method stub
       returnmAlbumList.size();
    }

   @Override
    publicObject getItem(int position) {
       // TODOAuto-generated method stub
       returnmAlbumList.get(position);
    }

   @Override
    public longgetItemId(int position) {
       // TODOAuto-generated method stub
       returnposition;
    }

   @SuppressLint("InflateParams") @Override
    public ViewgetView(int position, View convertView, ViewGroup parent) {
       // TODOAuto-generated method stub
      if(convertView == null) {
          convertView=LayoutInflater.from(mContext).inflate(R.layout.favorite_album_item,null);
          mViewHolder= new ViewHolder();
         mViewHolder.mImageView =(ImageView)convertView.findViewById(R.id.surface_img);
         mViewHolder.mTextView =(TextView)convertView.findViewById(R.id.favorite_album_name);
         convertView.setTag(mViewHolder);
       }
       else {
          mViewHolder= (ViewHolder)convertView.getTag();
       }
       final StringimageId = mAlbumList.get(position).getImageId();
      mViewHolder.mImageView.setTag(surfaceId);
       BitmapsurfaceBitmap =ImageProvider.getInstance().getBitmap(mContext,
            imageId,
             newILoadImageCallback() {

               @Override
                public voidonLoadImage(String id, Bitmap bitmap) {
                   // TODOAuto-generated method stub
                   ImageViewimageViewByTag =(ImageView)mGridView.findViewWithTag(imageId);
                  if(imageViewByTag != null) {
                     imageViewByTag.setImageBitmap(bitmap);
                   }
                }
             });
      if(surfaceBitmap != null) {
         mViewHolder.mImageView.setImageBitmap(surfaceBitmap);         
       }
      mViewHolder.mTextView.setText(mAlbumList.get(position).getmAlbumName());
       returnconvertView;
    }
   
    static classViewHolder {
       ImageViewmImageView;
       TextViewmTextView;
    }

}


这样异步的实现其实就是通过ILoadImageCallback接口的回调实现的,提供图片资源的类是ImageProvider。
这种设计方案的好处就是可以降低Adapter与ImageProvider的耦合性,方便了ImageProvider的封装与复用。同时Adapter的使用也比较方便。但是弊端也体现了出来,就是mGridView.findViewWithTag方法造成的性能的下降。
小编了解的其它的思路在性能方面可能会稍优于上面的方式,就是在需要异步的时候把mViewHolder.mImageView传递过去,并在图片获取的模块对ImageView进行更新。这样做会降低图片获取模块的复用性,所以在项目中小编木有设计成这种方式。。。
其实看客老爷们理解了上面博主对BaseAdapter的getView方法的原理之后,就可以看出,小编的代码已经尽量去提高效率与性能了。包括对convertView的复用以及ViewHolder的加入以减少大量的findViewById操作。但上面还有个地方没有做到效率的最佳,就在convertView=LayoutInflater.from(mContext).inflate(R.layout.favorite_album_item,null);这句代码。这句代码会在每次getView方法调用时都会通过LayoutInflater.from(mContext)创建一个LayoutInflater对象,造成了大量的对象浪费。最好还是在BaseAdapter类里直接声明一个LayoutInflater参数,并在构造方法中初始化它,以后就只用那一个对象就好了。
今天就废这么多话吧,相信看到这里的哥们儿们都已经不耐烦了。OK!我闭嘴,我滚蛋。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值