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

Android Studio如何基于日期实现动态Fragment,用ViewPager筛选Room数据

实现方案整体流程

1. 前置处理:Room日期字段统一格式化

先确保表中日期字段支持高效范围查询,推荐存储毫秒时间戳或者固定格式的日期字符串,实体类参考示例:

@Entity(tableName = "business_data")
data class BusinessData(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val content: String,
    // 存储毫秒时间戳,方便范围计算
    val dateTimestamp: Long,
    // 可选冗余字段,格式固定为yyyy-MM-dd,简化特殊场景查询
    val dateStr: String
)

2. 封装通用筛选Fragment

日/月/年维度的Fragment仅筛选条件不同,逻辑完全一致,直接封装可复用的通用Fragment,通过Bundle传递筛选参数:

class DateFilterFragment : Fragment() {
    companion object {
        private const val ARG_START_TIMESTAMP = "start_ts"
        private const val ARG_END_TIMESTAMP = "end_ts"

        fun newInstance(startTs: Long, endTs: Long): DateFilterFragment {
            val fragment = DateFilterFragment()
            val args = Bundle()
            args.putLong(ARG_START_TIMESTAMP, startTs)
            args.putLong(ARG_END_TIMESTAMP, endTs)
            fragment.arguments = args
            return fragment
        }
    }

    private lateinit var viewModel: BusinessViewModel
    private lateinit var dataAdapter: BusinessDataAdapter

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_date_filter, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 初始化列表和ViewModel
        dataAdapter = BusinessDataAdapter()
        binding.recyclerView.adapter = dataAdapter
        viewModel = ViewModelProvider(this)[BusinessViewModel::class.java]

        // 获取传入的时间范围参数
        val startTs = arguments?.getLong(ARG_START_TIMESTAMP) ?: 0
        val endTs = arguments?.getLong(ARG_END_TIMESTAMP) ?: 0

        // 查询对应范围的数据并渲染
        viewModel.getDataByTimeRange(startTs, endTs).observe(viewLifecycleOwner) {
            dataAdapter.submitList(it)
        }
    }
}

3. ViewPager + TabLayout 配置

3.1 布局引入

在承载页的XML布局中添加TabLayout和ViewPager,推荐使用官方更推荐的ViewPager2:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="scrollable" />

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

3.2 PagerAdapter实现

// 标签数据类,存储标签名和对应时间范围
data class TabItem(val title: String, val startTs: Long, val endTs: Long)

class FilterPagerAdapter(fragmentActivity: FragmentActivity, private val tabList: List<TabItem>) :
    FragmentStateAdapter(fragmentActivity) {
    override fun getItemCount() = tabList.size
    override fun createFragment(position: Int) = DateFilterFragment.newInstance(
        tabList[position].startTs,
        tabList[position].endTs
    )
}

3.3 按维度生成标签并绑定

// 示例:生成最近7天按日筛选的标签,按月/年筛选仅需调整时间计算规则即可
fun generateDayTabs(): List<TabItem> {
    val tabList = mutableListOf<TabItem>()
    val calendar = Calendar.getInstance()
    val dateFormat = SimpleDateFormat("MM/dd", Locale.getDefault())
    // 倒序生成7天数据
    for (i in 0 until 7) {
        calendar.set(Calendar.HOUR_OF_DAY, 0)
        calendar.set(Calendar.MINUTE, 0)
        calendar.set(Calendar.SECOND, 0)
        val startTs = calendar.timeInMillis
        val title = dateFormat.format(calendar.time)
        calendar.add(Calendar.DAY_OF_MONTH, 1)
        val endTs = calendar.timeInMillis
        tabList.add(TabItem(title, startTs, endTs))
        // 跳转到前一天
        calendar.add(Calendar.DAY_OF_MONTH, -2)
    }
    return tabList.reversed()
}

// Activity中绑定ViewPager和TabLayout
val tabList = generateDayTabs() // 切换维度时替换为对应生成方法即可
binding.viewPager.adapter = FilterPagerAdapter(this, tabList)
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
    tab.text = tabList[position].title
}.attach()

4. Room查询适配

在DAO层添加范围查询方法,支持不同维度筛选:

@Dao
interface BusinessDataDao {
    @Query("SELECT * FROM business_data WHERE dateTimestamp BETWEEN :startTs AND :endTs ORDER BY dateTimestamp DESC")
    suspend fun getDataByTimeRange(startTs: Long, endTs: Long): List<BusinessData>
}

ViewModel层封装查询逻辑:

class BusinessViewModel(private val dao: BusinessDataDao) : ViewModel() {
    fun getDataByTimeRange(startTs: Long, endTs: Long) = liveData {
        emit(dao.getDataByTimeRange(startTs, endTs))
    }
}

注意事项

  • 切换日/月/年筛选维度时,仅需重新生成对应规则的TabList,重新给ViewPager设置Adapter即可
  • 时间计算注意时区适配,避免出现日期偏移问题
  • 数据量较大时可给dateTimestamp字段添加索引,提升查询效率
  • 若使用旧版ViewPager,将Adapter替换为FragmentPagerAdapter/FragmentStatePagerAdapter即可,逻辑完全一致

内容的提问来源于stack exchange,提问作者Jayod Kavinda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 15:36:00