You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在RecyclerView中对比JSON返回日期,判断活动是否过期

Android DataBinding: 判断Deals是否过期并处理日期相关问题

针对你用DataBinding填充RecyclerView,需要判断Deals是否过期的需求,我来逐一解答你的疑问,并给出具体示例:


1. 应使用DATE还是String类型存储日期对象?

强烈推荐使用日期类型(比如LocalDateTime)而非String,原因如下:

  • String类型的日期无法直接进行比较,每次判断都要先解析成日期对象,重复操作不仅效率低,还容易因格式问题抛出异常;
  • 日期类型可以直接调用API进行时间对比,代码更简洁可靠;
  • DataBinding支持直接调用日期对象的方法,或者在实体类中封装判断逻辑,绑定到视图上非常方便。

实体类示例(Kotlin)

考虑到你的JSON日期格式是带UTC时区的ISO格式(如2018-04-27T03:06:18.890Z),我们可以用LocalDateTime配合DateTimeFormatter.ISO_OFFSET_DATE_TIME来解析:

import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter

data class DealsPageInfo(
    val DisplayName: String,
    val StartDate: String,
    val ExpiredDate: String,
    val Url: String,
    val ImageUrl: String,
    val ShortDescription: String
) {
    // 懒加载转换日期对象,避免重复解析
    private val startDateTime: LocalDateTime by lazy {
        LocalDateTime.parse(StartDate, DateTimeFormatter.ISO_OFFSET_DATE_TIME)
    }

    private val expiredDateTime: LocalDateTime by lazy {
        LocalDateTime.parse(ExpiredDate, DateTimeFormatter.ISO_OFFSET_DATE_TIME)
    }

    // 对外提供判断是否过期的方法,DataBinding可直接调用
    fun isExpired(): Boolean {
        // 用UTC时间对比,避免时区差异导致判断错误
        return expiredDateTime.isBefore(LocalDateTime.now(ZoneOffset.UTC))
    }
}

如果你是Java开发者,或者需要兼容Android 8.0以下版本,可以引入ThreeTenABP库来使用LocalDateTime,实体类写法类似:

import org.threeten.bp.LocalDateTime;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.format.DateTimeFormatter;

public class DealsPageInfo {
    private String DisplayName;
    private String StartDate;
    private String ExpiredDate;
    private String Url;
    private String ImageUrl;
    private String ShortDescription;

    // 转换后的日期对象
    private LocalDateTime startDateTime;
    private LocalDateTime expiredDateTime;

    public String getDisplayName() { return DisplayName; }
    public void setDisplayName(String displayName) { DisplayName = displayName; }
    public String getStartDate() { return StartDate; }
    public void setStartDate(String startDate) { StartDate = startDate; }
    public String getExpiredDate() { return ExpiredDate; }
    public void setExpiredDate(String expiredDate) { ExpiredDate = expiredDate; }
    // 其他字段的getter/setter...

    private LocalDateTime getStartDateTime() {
        if (startDateTime == null) {
            startDateTime = LocalDateTime.parse(getStartDate(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
        }
        return startDateTime;
    }

    private LocalDateTime getExpiredDateTime() {
        if (expiredDateTime == null) {
            expiredDateTime = LocalDateTime.parse(getExpiredDate(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
        }
        return expiredDateTime;
    }

    public boolean isExpired() {
        return getExpiredDateTime().isBefore(LocalDateTime.now(ZoneOffset.UTC));
    }
}

2. 该判断操作应在Fragment还是Adapter中执行?

优先推荐在实体类(Model)中封装判断逻辑,这样完全符合MVVM的设计思想,Fragment和Adapter只需要负责数据传递和视图绑定,不需要处理业务逻辑。如果一定要在Fragment和Adapter中二选一,Adapter是更合适的位置:

  • Fragment的职责是页面初始化、数据加载和整体页面控制,不应该处理单个列表项的视图状态判断;
  • Adapter负责每个RecyclerView item的视图绑定和状态控制,判断单个Deals是否过期属于item级别的逻辑,放在Adapter中更合理。

布局修改示例

在你的item布局中添加过期提示TextView,并通过DataBinding绑定显示状态:

<!-- 过期提示文本,仅当Deals过期时显示 -->
<TextView
    android:id="@+id/tv_expired_hint"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="DEALS EXPIRED"
    android:textColor="@color/red"
    android:textSize="@dimen/list_fontsize"
    android:visibility="@{offers.isExpired() ? View.VISIBLE : View.GONE}" />

<!-- 原有日期TextView,过期时隐藏 -->
<TextView
    android:id="@+id/list_offers_startDate"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginRight="3dp"
    android:text="@{offers.StartDate}"
    android:textColor="@color/colorGrayText"
    android:textSize="@dimen/list_fontsize"
    android:visibility="@{offers.isExpired() ? View.GONE : View.VISIBLE}" />

<TextView
    android:id="@+id/list_offers_endDate"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="3dp"
    android:text="@{offers.ExpiredDate}"
    android:textColor="@color/colorGrayText"
    android:textSize="@dimen/form_fontsize"
    android:visibility="@{offers.isExpired() ? View.GONE : View.VISIBLE}" />

RecyclerView Adapter示例(Kotlin)

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.yourpackage.databinding.ListOffersItemBinding

class DealsAdapter(private val dealsList: List<DealsPageInfo>) :
    RecyclerView.Adapter<DealsAdapter.DealsViewHolder>() {

    inner class DealsViewHolder(private val binding: ListOffersItemBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind(deal: DealsPageInfo) {
            binding.offers = deal
            // 立即执行绑定,避免视图更新延迟
            binding.executePendingBindings()
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DealsViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val binding = ListOffersItemBinding.inflate(inflater, parent, false)
        return DealsViewHolder(binding)
    }

    override fun onBindViewHolder(holder: DealsViewHolder, position: Int) {
        holder.bind(dealsList[position])
    }

    override fun getItemCount() = dealsList.size
}

最后补充

如果你的需求是需要过滤掉过期的Deals,那可以在Fragment中加载数据后先过滤,再传给Adapter;但如果是要标记过期状态,还是按照上面的方式处理更合理。

内容的提问来源于stack exchange,提问作者Shawn.Y

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:41:22