Android:BaseAdapter的优化方案一览

1.什么是数据适配器?

用来建立数据源和数据渲染控件之间的关系,将数据的来源和数据的显示之间进行解耦,降低耦合性

2.BaseAdapter接口

BaseAdapter是一个抽象类(abstract)【以下代码为android源码】

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    private final DataSetObservable mDataSetObservable = new DataSetObservable();
    private CharSequence[] mAutofillOptions;

    public boolean hasStableIds() {
        return false;
    }
    
    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }
    
    /**
     * Notifies the attached observers that the underlying data has been changed
     * and any View reflecting the data set should refresh itself.
     */
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

    /**
     * Notifies the attached observers that the underlying data is no longer valid
     * or available. Once invoked this adapter is no longer valid and should
     * not report further data set changes.
     */
    public void notifyDataSetInvalidated() {
        mDataSetObservable.notifyInvalidated();
    }

    public boolean areAllItemsEnabled() {
        return true;
    }

    public boolean isEnabled(int position) {
        return true;
    }

    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return getView(position, convertView, parent);
    }

    public int getItemViewType(int position) {
        return 0;
    }

    public int getViewTypeCount() {
        return 1;
    }
    
    public boolean isEmpty() {
        return getCount() == 0;
    }

    @Override
    public CharSequence[] getAutofillOptions() {
        return mAutofillOptions;
    }

    /**
     * Sets the value returned by {@link #getAutofillOptions()}
     */
    public void setAutofillOptions(@Nullable CharSequence... options) {
        mAutofillOptions = options;
    }
}

需要实现的抽象方法有四种

public int getCount() 适配器中数据集中数据的个数 listview显示的总数据
public Object getItem(int position) 获取数据集中与指定索引对应的数据项
public long getItemId(int position) 获取指定行对应的id
public View getView(int position,View convertView,ViewGroup parent):获取每一个Item显示的内容

3.如何使用BaseAdapter和ListView进行联动?

3-1:准备含ListView的总布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <ListView
        android:id="@+id/lv_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </ListView>
</LinearLayout>

3-2:准备ListView中呈现的item的布局()

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
<!--ListView的item布局-->
    <ImageView
        android:id="@+id/iv_image"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:src="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_toEndOf="@+id/iv_image"
        android:gravity="center"
        android:text="@string/tv_title"
        android:textSize="25sp" />

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_toEndOf="@id/iv_image"
        android:layout_below="@+id/tv_title"
        android:gravity="center_vertical"
        android:text="@string/string_tv_title"
        android:textSize="20sp" />

</RelativeLayout>

3-3:构建数据源:
 

package com.app.baseadaptertraining;
//构建数据源
public class ItemBean {
    public int itemImageResId;
    public String itemTitle;
    public String itemContent;
    //添加构造方法
    public ItemBean(int itemImageResId, String itemTitle, String itemContent) {
        this.itemImageResId = itemImageResId;
        this.itemTitle = itemTitle;
        this.itemContent = itemContent;
    }

}

3-4:实现数据适配器(可优化)

package com.app.baseadaptertraining;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

/**
 * BaseAdapter 抽象类
 */
public class MyAdapter extends BaseAdapter {
    private List<ItemBean> mList;
    private LayoutInflater mInflater;

    //进行数据的初始化
    //将数据源和数据适配器之间进行关联
    public MyAdapter(Context context, List<ItemBean> list) {
        mList = list;
        mInflater = LayoutInflater.from(context);
    }

    //返回ListView中的数据量
    @Override
    public int getCount() {
        return mList.size();
    }

    //取得所含有的数据项
    @Override
    public Object getItem(int position) {
        return mList.get(position);
    }

    //返回数据项的索引
    @Override
    public long getItemId(int position) {
        return position;
    }

    //返回每一项的内容
    //没有缓存机制
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //可以将xml文件装换称为view
        //开始装载视图
        /**
         * 每一次都是创建新的view,没有实现缓存机制 实现资源的极大浪费
         * 效率极其低下
         * View view=mInflater.inflate(R.layout.item,null);
         *         //找到视图中的三个控件
         *          ImageView imageView=(ImageView) view.findViewById(R.id.iv_image);
         *         TextView title=(TextView)view.findViewById(R.id.tv_title);
         *         TextView content=(TextView)view.findViewById(R.id.tv_content);
         *         ItemBean bean=mList.get(position);
         *         //开始进行数据的填充
         *         imageView.setImageResource(bean.itemImageResId);
         *         title.setText(bean.itemTitle);
         *         content.setText(bean.itemContent);
         * */
        //*******************************************************************
        //第一种优化方案:避免重复去创建view对象 但是fingViewById依旧会浪费大量的时间
//        if (convertView == null) {
//            convertView = mInflater.inflate(R.layout.item, null);
//        }
//            ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_image);
//            TextView title = (TextView) convertView.findViewById(R.id.tv_title);
//            TextView content = (TextView) convertView.findViewById(R.id.tv_content);
//            ItemBean bean = mList.get(position);
//            //开始进行数据的填充
//            imageView.setImageResource(bean.itemImageResId);
//            title.setText(bean.itemTitle);
//            content.setText(bean.itemContent);
//            return convertView;
        //*********************************************************************
        //第二种优化方案
        //1.避免convertView以及findViewById的优化
        //ViewHolder
        ViewHolder viewHolder;
        if (convertView == null) {
            viewHolder = new ViewHolder();
            convertView = mInflater.inflate(R.layout.item, null);
            //载入数据 findViewById()
            viewHolder.imageView = (ImageView) convertView.findViewById(R.id.iv_image);
            viewHolder.content = (TextView) convertView.findViewById(R.id.tv_content);
            viewHolder.title = (TextView) convertView.findViewById(R.id.tv_title);
            //ViewHolder和convertView进行关联

            convertView.setTag(viewHolder);
        } else {
            //取出关联的ViewHolder对象
            viewHolder = (ViewHolder) convertView.getTag();
        }
        ItemBean bean = mList.get(position);
        //开始进行数据的填充
        viewHolder.imageView.setImageResource(bean.itemImageResId);
        viewHolder.title.setText(bean.itemTitle);
        viewHolder.content.setText(bean.itemContent);
        return convertView;
    }

    //避免重复进行findViewById()
    //建立映射条件
    class ViewHolder {

        //对应布局中的三个控件
        public ImageView imageView;
        public TextView title;
        public TextView content;
    }
}

3-5:构建数据适配器和数据渲染器之间的联系(setAdapter)

package com.app.baseadaptertraining;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

/**
 * 1.准备含ListView的总布局文件
 * 2.准备单独的item文件
 * 3.构造数据源(bean/pojo)
 * 4.实现数据适配器 BaseAdapter
 * 5.建立Adapter和ListView之间的联系
 */
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        createMyList();
    }
    private void createMyList() {
        List<ItemBean> itemBeanList = new ArrayList<>();
        //封装数据(准备假的数据)
        for (int i = 0; i < 20; i++) {
            //进行数据的填充
            itemBeanList.add(new ItemBean(R.mipmap.ic_launcher, "这是一个title" + i, "这是一个content" + i));
        }
        //建立Adapter和ListView的联系
        ListView listView = (ListView) findViewById(R.id.lv_main);
        listView.setAdapter(new MyAdapter(this, itemBeanList));
    }
}

4.谈谈优化(主要是在构建Adapter的getView方法)

下面给出三种方案来构建视图

方案1:无优化,每一次均创建新的view,没有实现相应的缓存机制,实现资源的极大浪费

 public View getView(int position, View convertView, ViewGroup parent) {
        //可以将xml文件装换称为view
        //开始装载视图
        /**
         * 每一次都是创建新的view,没有实现缓存机制 实现资源的极大浪费
         * 效率极其低下
         * View view=mInflater.inflate(R.layout.item,null);
         *         //找到视图中的三个控件
         *          ImageView imageView=(ImageView) view.findViewById(R.id.iv_image);
         *         TextView title=(TextView)view.findViewById(R.id.tv_title);
         *         TextView content=(TextView)view.findViewById(R.id.tv_content);
         *         ItemBean bean=mList.get(position);
         *         //开始进行数据的填充
         *         imageView.setImageResource(bean.itemImageResId);
         *         title.setText(bean.itemTitle);
         *         content.setText(bean.itemContent);
                   return view;
         * */}

方案2:部分优化,借助自带的convertView进行优化

(判断convertView是否为空,从而杜绝每一次都要构建view的情况,但是重复findViewById()依旧会消耗极大的内存)

if (convertView == null) {
            convertView = mInflater.inflate(R.layout.item, null);
        }
            ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_image);
            TextView title = (TextView) convertView.findViewById(R.id.tv_title);
         ItemBean bean = mList.get(position);
            //开始进行数据的填充
            imageView.setImageResource(bean.itemImageResId);
            title.setText(bean.itemTitle);
            content.setText(bean.itemContent);
            return convertView;

方案3:全局优化,使用ViewHolder和convertView达到一种比较好的优化效果(相当于建立了两个缓存机制)

如果存在了视图组件,使用现成的convertView,无需重新创建

如果存在了控件,使用ViewHolder. 进行调用,无需重新查找控件位置

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
     
        //1.避免convertView以及findViewById的优化
        //ViewHolder
        ViewHolder viewHolder;
        if (convertView == null) {
            viewHolder = new ViewHolder();
            convertView = mInflater.inflate(R.layout.item, null);
            //载入数据 findViewById()
            viewHolder.imageView = (ImageView) convertView.findViewById(R.id.iv_image);
            viewHolder.content = (TextView) convertView.findViewById(R.id.tv_content);
            viewHolder.title = (TextView) convertView.findViewById(R.id.tv_title);
            //ViewHolder和convertView进行关联

            convertView.setTag(viewHolder);
        } else {
            //取出关联的ViewHolder对象
            viewHolder = (ViewHolder) convertView.getTag();
        }
        ItemBean bean = mList.get(position);
        //开始进行数据的填充
        viewHolder.imageView.setImageResource(bean.itemImageResId);
        viewHolder.title.setText(bean.itemTitle);
        viewHolder.content.setText(bean.itemContent);
        return convertView;
    }
 //避免重复进行findViewById()
    //建立映射条件
    class ViewHolder {

        //对应布局中的三个控件
        public ImageView imageView;
        public TextView title;
        public TextView content;
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值