Android中通用配器的使用

本文介绍了一种在Android开发中创建通用ListView适配器的方法,通过封装ViewHolder和BaseAdapter简化了ListView的创建流程。

1、简介
在Android开发过程中,我们经常需要写一些ListView和GridView等控件,如果给每一个都写一个适配器的话,过程无疑十分的枯燥,只会消耗大量的时间做这写毫无意义的事情,下面给大家介绍一个通用适配器。
2.一般的适配器的使用
普通的用法是:每一个ListView或者是GridView需要一个资源配置的XML文件,一个ViewHolder,一个普通的继承BaseAdapter的适配器。
1.布局文件

<ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
</ListView>

2.Item的布局文件:item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:text="您好!"/>
</RelativeLayout>

3.Adapter

package com.fly.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

/**
 * Created by fly on 2016/10/9.
 */

public class MyAdapter extends BaseAdapter {
    private Context context;
    private LayoutInflater inflater;
    private List<String> list;

    public MyAdapter(Context context, List<String> list) {
        this.context = context;
        this.list = list;
        inflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public String getItem(int position) {
        return list.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.item, parent);
            holder = new ViewHolder();
            holder.textView = (TextView) convertView.findViewById(R.id.textView);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.textView.setText(list.get(position));
        return convertView;
    }

    private class ViewHolder {
        TextView textView;
    }
}

相信大家对以上的写法并不陌生,估计有的人都已经写的要吐血了。下面给大家介绍一种通用的适配器。下面我们来总结一下写适配器的所需要的步骤:
1、现在主布局中添加一个ListView的控件;
2、编写一个Item的布局文件;
3、声明一个类继承BaseAdapter,并重写所需要重写的方法;
4、写一个ViewHoler的内部类,里面声明Item中的控件;当是第一次调用该适配器时存储控件,之后直接调用ViewHolder里面声明的控件,用来提高效率。
5、通过getView()方法来实现所需要的功能。
通过总结我们发现上面步骤中1~4完全相同,那么我们的问题来了:能不能将之前的第三步和第四步完全封装到一个类中,以方便我们使用呢?
答案当然是可以的,要不然我怎么接着往下写呢!

首先我们来换个思路,每一个适配器中都需要有一个ViewHolder,那么我们干脆写一个ViewHolder用来放置所有的控件。要放置很多个控件我们可以用到集合和数组,我们还需要通过特定的条件来找到该控件,不然我们怎么用。因此我们可以使用到Map集合来存储各种控件,通过控件的id来获取。有一个SparseArray是对Map集合的封装,是key为Integer的Map集合。因为我们所使用的控件的id都是int类型,所以可以使用该集合。
1、通用的ViewHolder

package com.fly.adapter;

import android.content.Context;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by fly on 2016/10/9.
 */

public class CommonViewHolder {
    //key是Integer类型的Map集合
    private SparseArray<View> mViews;
    private View convertView;

    private CommonViewHolder(Context context, ViewGroup parent, int layoutId, int position) {
        //初始化
        mViews = new SparseArray<>();
        //加载视图
        convertView = LayoutInflater.from(context).inflate(layoutId, parent,false);
        convertView.setTag(this);
    }
    //CommonViewHolder的入口方法
    public static CommonViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {
        if (convertView == null) {
            return new CommonViewHolder(context, parent, layoutId, position);
        }
        return (CommonViewHolder) convertView.getTag();
    }

    //这里是获取各种view
    public <T extends View> T getView(int viewId){
        View view = mViews.get(viewId);
        if (view == null) {
            view = convertView.findViewById(viewId);
            mViews.put(viewId,view);
        }
        return (T) view;
    }
    //获取convertView
    public View getConvertView(){
        return convertView;
    }
}

写完ViewHolder之后,可以在适配器中使用了,下面是之后的Adapter的代码:

package com.fly.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

/**
 * Created by fly on 2016/10/9.
 */

public abstract class CommonAdapter<T> extends BaseAdapter {
    protected Context context;
    protected List<T> list;
    protected LayoutInflater inflater;
    protected int itemLayoutId;

    public CommonAdapter(Context context, List<T> list, int itemLayoutId) {
        this.context = context;
        this.list = list;
        inflater.from(context);
        this.itemLayoutId = itemLayoutId;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public T getItem(int position) {
        return list.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //获取CommonViewHolder
        CommonViewHolder holder = getCommonViewHolder(position, convertView, parent);
        //通过getView()获取控件
        TextView textView = holder.getView(R.id.textView);
        textView.setText(getItem(position).toString());
        return holder.getConvertView();
    }
}

上面的代码可以根据需要传入不同的Java bean或者是类型,就不一一实现了。
下面开始写通用的适配器:
首先我们来分析一下写适配器的步骤:
1、传入一个Context对象;
2、传入一个LayoutInflater对象
3、传入一个List集合
4、根据需求在getView方法中写需求
这样的话我们其实是可以将getView方法提取出来,让其子类去实现该方法。这样的话代码就可以改成这样了:

package com.fly.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

/**
 * Created by lihb on 2016/10/9.
 */

public abstract class CommonAdapter<T> extends BaseAdapter {
    protected Context context;
    protected List<T> list;
    protected LayoutInflater inflater;
    protected int itemLayoutId;

    public CommonAdapter(Context context, List<T> list, int itemLayoutId) {
        this.context = context;
        this.list = list;
        inflater.from(context);
        this.itemLayoutId = itemLayoutId;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public T getItem(int position) {
        return list.get(position);
    }

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

    @Override
    public abstract View getView(int position, View convertView, ViewGroup parent);
}
package com.fly.picasso;

import android.content.Context;
import android.widget.TextView;

import java.util.List;

/**
 * Created by fly on 2016/9/30.
 */

public class MyAdapter extends CommonAdapter {

    public MyAdapter(Context context, List list, int itemLayoutId) {
        super(context, list, itemLayoutId);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //获取CommonViewHolder
        CommonViewHolder holder = getCommonViewHolder(position, convertView, parent);
        //通过getView()获取控件
        TextView textView = holder.getView(R.id.textView);
        textView.setText(getItem(position).toString());
        return holder.getConvertView();
    }
}

这样的话一个简单的通用适配器就完成了。

<think>好的,我现在需要帮助用户了解STL中的空间配置器allocator的原理和使用方法。首先,我得回顾一下用户提供的引用内容,确保回答准确。引用中提到了不同STL实现中的allocator,比如SGI STL的一级和二级配置器,特别是二级配置器的内存池机制。用户可能想知道allocator的基本概念、为什么需要它,以及具体的工作原理。 首先,我应该从allocator的定义开始,说明它在STL中的作用,比如负责内存分配和释放,与容器紧密相关。然后,区分默认allocator和SGI的实现,特别是内存池的设计,这可能涉及一级配置器处理大内存,二级处理小内存,避免碎片化。需要解释为什么需要这样的设计,比如效率问题。 接下来,用户可能需要知道如何使用allocator,比如在容器中如何指定,或者自定义allocator的情况。但根据引用内容,默认情况下用户可能不感知,但可以自定义。引用4提到了一些兼容性问题,比如不同STL版本对allocator的要求不同,可能需要说明。 还需要注意代码示例,但用户的问题可能更多是原理而非代码,不过引用5提到了GitHub上的源码,或许可以提及但不需要深入。另外,用户的问题包括使用和原理,所以需要两部分结构。 可能需要提到的点包括:allocator的基本职责、SGI的两级配置器、内存池的工作机制、与new/delete的区别、自定义allocator的可能性。同时,引用中提到PJ STL和RW STL的兼容性问题,这可能属于高级内容,但用户可能需要了解不同实现的差异。 最后,生成相关问题时要围绕allocator的应用场景、优缺点、与智能指针的关系,以及内存池的具体实现方式。确保问题能够引导进一步学习。 在回答时,要结构清晰,分点讲解,确保原理部分有层次,使用场景和自定义方法部分实用。注意使用中文,LaTeX格式正确,数学表达式用$...$,独立公式用$$...$$,但当前问题可能较少涉及数学公式,但如果有涉及内存分配算法可能需要。 现在组织内容,确保覆盖所有关键点,引用正确,并且语言流畅自然。</think>### STL空间配置器allocator的原理与使用 #### 一、基本概念 空间配置器(allocator)是STL容器的底层内存管理工具,负责内存的分配与释放。所有STL容器(如`vector`、`list`等)都隐式依赖allocator,但用户通常无需显式调用[^3][^5]。 #### 二、核心原理 1. **默认allocator** C++标准库提供默认的`std::allocator`,直接封装`new`和`delete`,但效率较低(频繁申请小块内存易产生碎片)[^1]。 2. **SGI STL的两级配置器** SGI实现通过优化提升性能: - **一级配置器**:处理大内存请求(直接调用`malloc`和`free`) - **二级配置器**:使用**内存池**管理小块内存(小于128字节),减少系统调用和碎片[^2][^4]。 内存池工作机制: ```plaintext 1. 预分配大块内存作为备用 2. 维护16个自由链表(8~128字节,以8字节递增) 3. 请求内存时,从对应链表中分配;释放时回收到链表 ``` 3. **优势对比** | 方式 | 优点 | 缺点 | |---------------|-------------------------|--------------------------| | `new/delete` | 简单通用 | 频繁分配小块内存效率低 | | SGI allocator | 减少碎片,降低系统调用 | 实现复杂,需适配特定STL | #### 三、使用方法 1. **显式指定allocator** ```cpp std::vector<int, MyAllocator<int>> vec; // 使用自定义allocator ``` 2. **自定义allocator要求** - 实现`allocate()`、`deallocate()`等方法 - 需满足STL标准接口(如`rebind`机制)[^4][^5] #### 四、兼容性问题 不同STL实现(如PJ STL、RW STL)对allocator的接口要求不同,SGI的配置器无法直接适配其他版本[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值