第一次接触安卓,在AI帮助下,实现一个倒计时APP

倒计时应用开发实践:从零到完整功能实现

在移动应用开发中,倒计时功能是一个非常实用的场景,比如纪念日、考试、活动倒计时等。最近,我利用AI完成了一个基于 Android 的倒计时应用,它支持本地数据存储、动态计算剩余天数、支持添加、编辑和删除倒计时。

项目功能概述

这个倒计时应用的核心功能包括:

  1. 本地数据存储:使用 SQLite 数据库保存倒计时数据。

  2. 动态日期计算:实时计算目标日期与当前日期之间的剩余天数。

  3. 用户交互:支持添加、编辑和删除倒计时。

  4. UI 更新:每秒更新当前时间和日期,并动态刷新倒计时天数。

核心技术点

1. SQLite 数据库的使用

在 Android 中,SQLite 是一个轻量级的嵌入式数据库,非常适合本地数据存储。我创建了一个 DatabaseHelper 类来管理数据库操作。

java

复制

java 复制代码
public class DatabaseHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "countdown.db";
    private static final int DATABASE_VERSION = 1;

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String CREATE_TABLE = "CREATE TABLE countdowns (" +
                "id INTEGER PRIMARY KEY AUTOINCREMENT," +
                "title TEXT," +
                "target_date INTEGER)";
        db.execSQL(CREATE_TABLE);
    }

    public long addCountdown(CountdownItem item) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("title", item.getTitle());
        values.put("target_date", item.getTargetDate().getTime());
        long id = db.insert("countdowns", null, values);
        db.close();
        return id;
    }

    public List<CountdownItem> getAllCountdowns() {
        List<CountdownItem> items = new ArrayList<>();
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery("SELECT * FROM countdowns", null);
        // 数据处理逻辑
        return items;
    }
}
  • 表结构设计countdowns 表包含 id(主键)、title(标题)和 target_date(目标日期的时间戳)。

  • CRUD 操作 :通过 addCountdown 添加数据,getAllCountdowns 查询所有数据,updateCountdown 更新数据,deleteCountdown 删除数据。

2. 日期计算与格式化

日期计算是倒计时应用的核心功能之一。我使用了 DateCalendar 类来处理日期,并通过 SimpleDateFormat 格式化日期和时间。

java

复制

typescript 复制代码
public class DateUtils {
    public static String formatDate(Date date) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault());
        return dateFormat.format(date);
    }

    public static long getDaysBetween(Date startDate, Date endDate) {
        long diff = endDate.getTime() - startDate.getTime();
        return diff / (24 * 60 * 60 * 1000);
    }

    public static boolean isFutureDate(Date date) {
        return date.after(new Date());
    }
}
  • 日期格式化 :将日期格式化为 yyyy/MM/ddHH:mm:ss

  • 天数计算:通过时间戳差值计算剩余天数。

  • 未来日期判断:确保用户选择的目标日期是未来的日期。

3. UI 动态更新

为了实现倒计时天数的动态更新,我使用了 HandlerRunnable 来每秒刷新 UI。

java

复制

ini 复制代码
private void setupTimeUpdates() {
    Handler timeHandler = new Handler();
    Runnable timeRunnable = new Runnable() {
        @Override
        public void run() {
            updateDateTime();
            timeHandler.postDelayed(this, 1000);
        }
    };
    timeHandler.postDelayed(timeRunnable, 1000);
}

private void updateDateTime() {
    Date now = new Date();
    timeTextView.setText(DateUtils.formatDateTime(now));
    dateTextView.setText(DateUtils.formatDate(now) + " " + DateUtils.formatDayOfWeek(now));

    for (int i = 0; i < countdownItems.size(); i++) {
        CountdownItem item = countdownItems.get(i);
        long daysLeft = DateUtils.getDaysBetween(now, item.getTargetDate());
        adapter.notifyItemChanged(i);
    }
}
  • Handler 和 Runnable :每秒触发一次 updateDateTime 方法。

  • UI 刷新:更新当前时间和日期,并重新计算所有倒计时的剩余天数。

4. RecyclerView 的使用

RecyclerView 是 Android 中用于展示列表数据的高效组件。我使用它来展示倒计时列表,并支持编辑和删除操作。

java

复制

less 复制代码
public class CountdownAdapter extends RecyclerView.Adapter<CountdownAdapter.ViewHolder> {
    private List<CountdownItem> items;
    private MainActivity activity;

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        CountdownItem item = items.get(position);
        Date now = new Date();
        long daysLeft = DateUtils.getDaysBetween(now, item.getTargetDate());

        holder.titleTextView.setText(item.getTitle());
        holder.daysLeftTextView.setText(String.format("距离 %s %s 还有 %d天",
                DateUtils.formatDate(item.getTargetDate()),
                DateUtils.formatDayOfWeek(item.getTargetDate()),
                daysLeft));

        holder.editButton.setOnClickListener(v -> activity.editCountdown(position));
        holder.deleteButton.setOnClickListener(v -> activity.deleteCountdown(position));
    }
}
  • 数据绑定:将倒计时数据绑定到列表项。

  • 用户交互:通过按钮点击事件实现编辑和删除功能。

xml文件

添加图标

arduino 复制代码
<vector xmlns:android="http://schemas.android.com/apk/res/android"    android:width="24dp"    android:height="24dp"    android:viewportWidth="24"    android:viewportHeight="24">    <path        android:fillColor="#FF000000"        android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></vector>

删除图标

arduino 复制代码
<vector xmlns:android="http://schemas.android.com/apk/res/android"    android:width="24dp"    android:height="24dp"    android:viewportWidth="24"    android:viewportHeight="24">    <path        android:fillColor="#FF000000"        android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6V19zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/></vector>

设置图标

arduino 复制代码
<vector xmlns:android="http://schemas.android.com/apk/res/android"    android:width="24dp"    android:height="24dp"    android:viewportWidth="24"    android:viewportHeight="24">    <path        android:fillColor="#FF000000"        android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94 0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61 l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41 h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22 L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58 c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54 c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96 c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6 s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/></vector>

设置页面

xml 复制代码
<?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"    android:orientation="vertical"    android:padding="16dp"    tools:context=".activities.EditActivity">    <TextView        android:id="@+id/titleLabel"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:textSize="20sp"        android:text="# 未设置标题"        android:layout_marginBottom="16dp"/>    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="请输入计时器的名称"        android:layout_marginBottom="8dp"/>    <EditText        android:id="@+id/titleEditText"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:hint="标题"        android:layout_marginBottom="24dp"/>    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="目标日期"        android:layout_marginBottom="8dp"/>    <Button        android:id="@+id/dateButton"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="2025/06/14"/>    <View        android:layout_width="match_parent"        android:layout_height="1dp"        android:background="@android:color/darker_gray"        android:layout_marginVertical="16dp"/>    <Button        android:id="@+id/saveButton"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="保存"        android:layout_marginTop="16dp"/></LinearLayout>

主页面

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"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:padding="16dp"    tools:context=".activities.MainActivity">    <LinearLayout        android:id="@+id/header"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:orientation="vertical"        android:layout_marginBottom="24dp">        <TextView            android:id="@+id/timeTextView"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:textSize="24sp"            android:text="18:15:25"/>        <TextView            android:id="@+id/dateTextView"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:textSize="16sp"            android:text="2025/04/14 星期一"/>    </LinearLayout>    <androidx.recyclerview.widget.RecyclerView        android:id="@+id/countdownRecyclerView"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_below="@id/header"        android:layout_above="@+id/addButton"/>    <com.google.android.material.floatingactionbutton.FloatingActionButton        android:id="@+id/addButton"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_alignParentEnd="true"        android:layout_margin="16dp"        app:srcCompat="@drawable/ic_add"        app:tint="@android:color/white"/></RelativeLayout>

列表部分

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="wrap_content"    android:padding="16dp"    android:background="?android:attr/selectableItemBackground"    android:clickable="true"    android:focusable="true">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_toStartOf="@+id/actionButtons"        android:orientation="vertical">        <TextView            android:id="@+id/titleTextView"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:textSize="18sp"            android:text="这里是title"/>        <TextView            android:id="@+id/daysLeftTextView"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:textSize="14sp"            android:text="距离 2025/06/14 星期二 还有 50天"/>    </LinearLayout>    <LinearLayout        android:id="@+id/actionButtons"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentEnd="true"        android:orientation="horizontal">        <ImageButton            android:id="@+id/editButton"            android:layout_width="40dp"            android:layout_height="40dp"            android:background="?attr/selectableItemBackgroundBorderless"            app:srcCompat="@drawable/ic_settings"            app:tint="@android:color/darker_gray"/>        <ImageButton            android:id="@+id/deleteButton"            android:layout_width="40dp"            android:layout_height="40dp"            android:background="?attr/selectableItemBackgroundBorderless"            app:srcCompat="@drawable/ic_delete"            app:tint="@android:color/darker_gray"/>    </LinearLayout></RelativeLayout>

开发环境与工具

  • Android Studio:版本 4.2.2,用于项目开发和调试。

  • Gradle:版本 6.7.1,用于项目构建。

  • JDK:版本 20,用于 Java 代码编译。

  • 依赖库

    • androidx.appcompat:appcompat:1.4.1

    • com.google.android.material:material:1.5.0

    • androidx.recyclerview:recyclerview:1.2.1

总结

这是我第一次接触安卓项目,主要还是通过AI实现的,本文章旨在分享以及记录,如若有什么不妥的地方,还望各位大佬点评,谢谢大家。

相关推荐
时光少年1 小时前
Android 副屏录制方案
android·前端
时光少年1 小时前
Android 局域网NIO案例实践
android·前端
alexhilton1 小时前
Jetpack Compose的性能优化建议
android·kotlin·android jetpack
流浪汉kylin1 小时前
Android TextView SpannableString 如何插入自定义View
android
火柴就是我3 小时前
git rebase -i,执行 squash 操作 进行提交合并
android
你说你说你来说4 小时前
安卓广播接收器(Broadcast Receiver)的介绍与使用
android·笔记
你说你说你来说4 小时前
安卓Content Provider介绍及使用
android·笔记
RichardLai884 小时前
[Flutter学习之Dart基础] - 类
android·flutter
_一条咸鱼_5 小时前
深度解析 Android MVI 架构原理
android·面试·kotlin
火柴就是我5 小时前
git rebase -i 修改某次提交的message
android