蜗牛君漫聊动态布局框架(二):核心功能的思路与实现

本文深入探讨动态布局框架的核心思想,基于Android的RecyclerView,讲解如何使用工厂模式设计Adapter,通过getItemViewType确定数据类型,并用HashMap存储ViewHolder对应关系,结合反射机制动态创建ViewHolder。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hello! 大家好,我是蜗牛君~ 我们又见面了,本篇文章是蜗牛君漫聊动态布局框架的第二篇。上一篇中我们讲解了框架的大致思路,以及复习了一下RecyclerView的基础使用方式。那么本篇文章我们就正式开始框架的搭建了。

首先我们要做一件事情,就是捋清楚整个框架的搭建思路。

思路讲解

1、思路的起点:getItemViewType(int position)方法

只要是有Android原生开发经验的朋友都知道在RecyclerView出现之前,我们一直熟练使用的是ListView,为了解决ListView的一些不理想之处,所以出现了RecyclerView,但是ListView的大部分功能RecyclerView还是继承了。蜗牛君在很久之前使用ListView做开发时就遇到过一个需求,在新闻列表中要穿插广告,广告的布局样式和新闻布局完全不同,这个需求很常见,所以蜗牛君在网上很轻易的就查到了大量的文章,这些文章的内容大同小异,他们都有一个共同点,那就是使用Adapter的getItemViewType(int position)方法。

于是蜗牛君就在网上查了一下这个方法的用途。大概意思就是说在Adapter创建ViewHolder之前,会先通过getItemViewType方法判断数据的类型,可以根据getItemViewType方法不同的返回值,确定加载不同的ViewHolder。因此,getItemViewType方法就是思路的起点。

那我们在getItemViewType方法中做什么呢?由于getItemViewType方法的返回值是int类型,因此这个int类型的值要能够确定ViewHolder的具体类型。

2、数据类型和ViewHolder类型对应关系的存储

我们框架的原理就是根据不同类型的数据选择不同类型的ViewHolder,因此这份一一对应的关系如何存储至关重要。

我们的思路是使用HashMap集合,数据类型的Class类为Key值,ViewHolder类的Class类为Value值,这样就把一一对应的关系存储起来了。

既然我们存储的是Class类,因此在实例化的时候就需要用到Java的反射机制了,这也就是动态的体现。

3、数据和ViewHolder对应关系的查询

在HashMap集合中,Key值是数据类型的Class类,我们接下来要思考的问题是如何确定Key值。上文提到过,getItemViewType方法返回的数据类型是int类型,而我们HashMap中存储的Key值是Class类型,这完全不匹配啊!我们的策略是中间增加一层,建立Key值的索引目录。

具体来讲就是,我们在初始化时,要进行一步存储操作,这步操作包含两项:第一项就是将数据类型的Class类依次存入ArrayList集合;第二项是依次将数据与ViewHolder的对应关系存入HashMap;有了存储所有数据类型Class类的ArrayList集合,我们就可以确定当前Item的数据类型是否存在,存在的话又是什么。确定了数据的Class类,就能从HashMap中获取到对应ViewHolder的Class类。

4、程序的设计

对于ViewHolder的创建,我们使用工厂模式,不同类型的ViewHolder是我们要生产的产品,我们还需要一个生产ViewHolder的工厂,对于工厂模式的基本结构这里不再赘述。

对外提供使用方法的时候,使用建造者模式,以此达到链式调用的目的。

代码实现:框架的核心功能—工厂模式

1、工厂模式中的抽象产品类:BaseViewHolder

需要做到以下几点:

  • 继承官方RecyclerView.ViewHolder类;
  • 以泛型的方式传递要绑定的数据类型;
  • 重写构造方法;
  • 重载构造方法;
  • 填充Item布局文件(以参数形式);
  • 绑定数据到Item布局(以参数形式);
/**
 * 工厂模式中---抽象产品类
 *
 * 职责:
 * 1、填充Item布局文件;
 * 2、绑定数据到Item布局
 *
 * @param <V> 需要绑定的数据类型
 */
public abstract class BaseViewHolder<V> extends RecyclerView.ViewHolder {
    /**
     * 自定义构造方法
     * 
     * 无论是ListView还是RecyclerView,我们都是使用LayoutInflater的方式填充Item的布局
     * 因此这里要传递的参数是Context、ViewGroup、LayoutId
     * 
     * @param context
     * @param parent
     * @param layoutId
     */
    public BaseViewHolder(Context context, ViewGroup parent, int layoutId) {
        this(LayoutInflater.from(context).inflate(layoutId, parent, false));
    }

    public BaseViewHolder(@NonNull View itemView) {
        super(itemView);
        // 使用ButterKnife绑定布局文件
        ButterKnife.bind(this,itemView);
    }

    /**
     * ViewHolder与数据进行绑定
     *
     * @param position
     * @param value
     * @param adapter
     */
    public abstract void bindTo(int position, V value, RecyclerAdapter adapter);
}

注意

  • 我们使用了ButterKnife进行布局关联;
  • 抽象方法bindTo中的参数定义,value是必须的,这是我们进行绑定的具体数据,其他参数可根据业务需要进行修改,具体实现由子类完成;
2、工厂模式中的具体产品类—CommonViewHolder

需要做到一下几点:

  • 传递具体ViewHolder所要绑定的数据类型给父类;
  • 重载父类的构造方法,确定了父类构造方法中三个参数里面的layoutId的值;
  • 进行真正的数据与布局的绑定工作;
/**
 * ViewHolder具体实现类
 */
public class CommonViewHolder extends BaseViewHolder<CommonModel> {
    @BindView(R.id.txt_content)
    TextView mTxtContent;

    /**
     * 重载构造方法,确定LayoutId参数值
     * 
     * @param context
     * @param parent
     */
    public CommonViewHolder(Context context, ViewGroup parent) {
        super(LayoutInflater.from(context).inflate(R.layout.recycler_view_item_common, parent, false));
    }
    
    @Override
    public void bindTo(int position, CommonModel value, RecyclerAdapter adapter) {
        mTxtContent.setText(value.content);
    }
}

recycler_view_item_common.xml(使用ConstraintLayout布局)

<TextView
    android:id="@+id/txt_content"
    android:layout_width="wrap_content"
    android:layout_height="30dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginBottom="8dp"
    android:text="TextView"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.097"
    tools:ignore="MissingConstraints" />
3、工厂模式中的具体工厂类—ViewHolderFactory

因为我们模块只需要一个工厂类,因此不必设置抽象工厂类。

需要做到以下几点:

  • 数据类型与ViewHolder对应关系的存储策略:
    创建List类型的索引集合,用来存储所有数据的具体类型;创建Map类型的ViewHolder集合,Key值为数据的具体类型,Value值为ViewHolder的具体类型。
  • 动态创建ViewHolder的核心技术:Java的反射机制。
  • 封装对外提供的基本方法。
/**
 * ViewHolder工厂类
 */
public class ViewHolderFactory {
    private Context mContext;
    // 数据类型的Class类作为索引被存储在集合中
    private List<Class> valueClassType = new ArrayList<>();
    // 数据类型的Class类为Key值,需要绑定的ViewHolder类型的Class类为Value值
    private Map<Class, Class<? extends BaseViewHolder>> boundViewHolder = new HashMap<>();

    /**
     * 构造方法,需要传递上下文
     * 
     * @param context
     */
    public ViewHolderFactory(Context context) {
        mContext = context;
    }

    /**
     * 创建ViewHolder
     *
     * @param viewType Map中的Key值所在List集合中的下标
     * @param parent
     * @return
     */
    public BaseViewHolder create(int viewType, ViewGroup parent) {
        Class valueClass = valueClassType.get(viewType);
        try {
            Class<? extends BaseViewHolder> viewHolderClass = boundViewHolder.get(valueClass);
            Constructor<? extends BaseViewHolder> constructor = viewHolderClass.getDeclaredConstructor(Context.class, ViewGroup.class);
            return constructor.newInstance(mContext, parent);
        } catch (Exception e) {
            throw new RuntimeException("Unable to create ViewHolder for " + valueClass + "."
                    + e.getCause().getMessage(), e);
        }
    }

    /**
     * 存储ViewHolder索引,存储ViewHolder
     *
     * @param valueClass
     * @param viewHolder
     */
    public void bind(Class valueClass, Class<? extends BaseViewHolder> viewHolder) {
        // 存储索引值
        valueClassType.add(valueClass);
        // 存储ViewHolder
        boundViewHolder.put(valueClass, viewHolder);
    }

    /**
     * 查询指定数据类型在索引集合中的下标,有下标就能在Map中找到对应的ViewHolder类型
     *
     * @param object
     * @return
     */
    public int itemViewType(Object object) {
        return valueClassType.indexOf(object.getClass());
    }

    /**
     * 获取索引集合
     *
     * @return
     */
    public List<Class> getValueClassType() {
        return valueClassType;
    }

    /**
     * 获取ViewHolder集合
     *
     * @return
     */
    public Map<Class, Class<? extends BaseViewHolder>> getBoundViewHolder() {
        return boundViewHolder;
    }
}

以上就是框架核心功能工厂模式的全部代码了,由于篇幅原因,本篇文章先介绍到这里。上述内容有一定的难度,首先第一步要做到的就是缕清思路,理解制定的方案与意图。第二步就是一些基础知识的获取,工厂模式的相关知识,Java反射机制的相关知识等等。好了,蜗牛君想说的就这么多,我们下篇文章见。

在这里插入图片描述

内容概要:本文针对火电厂参直购交易挤占风电上网空间的问题,提出了一种风火打捆参大用户直购交易的新模式。通过分析可再生能源配额机制下的双边博弈关系,建立了基于动态非合作博弈理论的博弈模型,以直购电价和直购电量为决策变量,实现双方收益均衡最大化。论文论证了纳什均衡的存在性,并提出了基于纳什谈判法的风-火利益分配方法。算例结果表明,该模式能够增加各方收益、促进风电消纳并提高电网灵活性。文中详细介绍了模型构建、成本计算和博弈均衡的实现过程,并通过Python代码复现了模型,包括参数定义、收益函数、纳什均衡求解、利益分配及可视化分析等功能。 适合人群:电力系统研究人员、能源政策制定者、从事电力市场交易的工程师和分析师。 使用场景及目标:①帮助理解风火打捆参大用户直购交易的博弈机制;②为电力市场设计提供理论依据和技术支持;③评估不同政策(如可再生能源配额)对电力市场的影响;④通过代码实现和可视化工具辅助教学和研究。 其他说明:该研究不仅提供了理论分析,还通过详细的代码实现和算例验证了模型的有效性,为实际应用提供了参考。此外,论文还探讨了不同场景下的敏感性分析,如证书价格、风电比例等对市场结果的影响,进一步丰富了研究内容。
资源下载链接为: https://pan.quark.cn/s/d37d4dbee12c A:计算机视觉,作为人工智能领域的关键分支,致力于赋予计算机系统 “看懂” 世界的能力,从图像、视频等视觉数据中提取有用信息并据此决策。 其发展历程颇为长。早期图像处理技术为其奠基,后续逐步探索三维信息提取,人工智能结合,又经历数学理论深化、机器学习兴起,直至当下深度学习引领浪潮。如今,图像生成和合成技术不断发展,让计算机视觉更深入人们的日常生活。 计算机视觉综合了图像处理、机器学习、模式识别和深度学习等技术。深度学习兴起后,卷积神经网络成为核心工具,能自动提炼复杂图像特征。它的工作流程,首先是图像获取,用相机等设备捕获视觉信息并数字化;接着进行预处理,通过滤波、去噪等操作提升图像质量;然后进入关键的特征提取和描述环节,提炼图像关键信息;之后利用这些信息训练模型,学习视觉模式和规律;最终用于模式识别、分类、对象检测等实际应用。 在实际应用中,计算机视觉用途极为广泛。在安防领域,能进行人脸识别、目标跟踪,保障公共安全;在自动驾驶领域,帮助车辆识别道路、行人、交通标志,实现安全行驶;在医疗领域,辅助医生分析医学影像,进行疾病诊断;在工业领域,用于产品质量检测、机器人操作引导等。 不过,计算机视觉发展也面临挑战。比如图像生成技术带来深度伪造风险,虚假图像和视频可能误导大众、扰乱秩序。为此,各界积极研究检测技术,以应对这一问题。随着技术持续进步,计算机视觉有望在更多领域发挥更大作用,进一步改变人们的生活和工作方式 。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值