用Kotlin写一个Android闹钟

ai写的,还是调试了一下,有些问题要多次追问。记录下来,下次好用。

复制代码
package com.example.myclock

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.example.myclock.ui.theme.MyClockTheme
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import java.util.*
import android.content.BroadcastReceiver
import android.media.MediaPlayer
import android.media.RingtoneManager
import android.widget.Toast
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.TextField


// 添加全局状态管理类
object AlarmStateManager {
    // 定义一个公共变量,用于表示闹钟是否处于激活状态
    public var isAlarmActive = false
    // 定义一个私有变量,用于存储MediaPlayer对象
    private var mediaPlayer: MediaPlayer? = null
    // 定义一个私有变量,用于存储上下文对象
    private var context: Context? = null

    // 初始化方法,用于设置上下文对象
    fun initialize(context: Context) {
        this.context = context
    }

    // 激活闹钟的方法
    fun activateAlarm() {
        // 检查闹钟是否未激活且上下文对象不为空
        if (!isAlarmActive && context != null) {
            // 设置闹钟为激活状态
            isAlarmActive = true
            // 创建一个MediaPlayer对象,并设置默认的闹钟铃声
            mediaPlayer = MediaPlayer.create(context, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM))
            // 开始播放铃声
            mediaPlayer?.start()
        }
    }

    // 停用闹钟的方法
    fun deactivateAlarm() {
        // 设置闹钟为未激活状态
        isAlarmActive = false
        // 释放MediaPlayer对象
        mediaPlayer?.release()
        // 将MediaPlayer对象置为null
        mediaPlayer = null
    }
}
class MainActivity : ComponentActivity() {
    // 重写onCreate方法,这是Activity生命周期中的第一个方法
    override fun onCreate(savedInstanceState: Bundle?) {
        // 调用父类的onCreate方法,确保Activity正确初始化
        super.onCreate(savedInstanceState)
        // 启用Edge-to-Edge模式,使内容延伸到屏幕边缘
        enableEdgeToEdge()
        AlarmStateManager.initialize(this) // 初始化状态管理器
        // 设置应用程序的内容
        setContent {
            // 应用自定义的主题 MyClockTheme
            MyClockTheme {
                // 使用 MaterialTheme 的背景颜色创建一个 Surface
                Surface(color = MaterialTheme.colorScheme.background) {
                    // 创建并显示 AlarmScreen 组件
                    // 传递 applicationContext 作为上下文
                    // 传递一个 lambda 表达式作为 onDismissAlarm 参数,当闹钟被解除时调用 AlarmStateManager.deactivateAlarm()
                    AlarmScreen(
                        context = applicationContext,
                        onDismissAlarm = { AlarmStateManager.deactivateAlarm() }
                    )
                }
            }
        }
    }

}

@Composable
// 定义一个名为 AlarmScreen 的函数,接收一个 Context 对象和一个无参数的回调函数 onDismissAlarm
fun AlarmScreen(context: Context, onDismissAlarm: () -> Unit) {
    // 使用 remember 和 mutableStateOf 创建一个可变状态变量 timeInput,用于存储用户输入的时间
    var timeInput by remember { mutableStateOf("") }

    // 使用 Column 布局,使其子视图在垂直方向上居中对齐,并在水平方向上居中对齐
    Column(
        modifier = Modifier.fillMaxSize(), // 填满整个屏幕
        verticalArrangement = Arrangement.Center, // 垂直方向居中对齐
        horizontalAlignment = Alignment.CenterHorizontally // 水平方向居中对齐
    ) {
        // 显示提示文本,要求用户输入时间
        Text(text = "请输入时间 (HH:mm):")
        // 创建一个 TextField,用于用户输入时间
        TextField(
            value = timeInput, // 绑定到 timeInput 状态变量
            onValueChange = { timeInput = it }, // 当输入值改变时,更新 timeInput 状态变量
            label = { Text("输入时间") } // 设置输入框的标签
        )

        // 创建一个按钮,点击时设置闹钟
        Button(onClick = {
            // 将输入的时间字符串按 ":" 分割成小时和分钟
            val timeParts = timeInput.split(":")
            // 检查分割后的数组长度是否为 2
            if (timeParts.size == 2) {
                // 尝试将小时和分钟转换为整数
                val hour = timeParts[0].toIntOrNull()
                val minute = timeParts[1].toIntOrNull()
                // 检查转换结果是否为非空
                if (hour != null && minute != null) {
                    // 调用 setAlarm 函数设置闹钟
                    setAlarm(context, hour, minute)
                    // 显示一个 Toast 提示用户闹钟已设置
                    Toast.makeText(context, "闹钟已设置", Toast.LENGTH_SHORT).show()
                }
            }

        }) {
            // 按钮上显示的文本
            Text("设置闹钟")
        }
        // 根据全局状态显示提示和按钮
        Button(onClick = onDismissAlarm) {
            Text("停止")
        }
    }
}
// 定义一个函数setAlarm,用于设置闹钟
fun setAlarm(context: Context, hour: Int, minute: Int) {
    // 获取系统的闹钟管理服务
    val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
    // 创建一个Intent,指向AlarmReceiver类,用于接收闹钟广播
    val intent = Intent(context, AlarmReceiver::class.java)
    // 创建一个PendingIntent,用于延迟执行Intent
    val pendingIntent = PendingIntent.getBroadcast(
        context,
        0,
        intent,
        // PendingIntent.FLAG_IMMUTABLE表示PendingIntent不可变,FLAG_UPDATE_CURRENT表示更新当前已有的PendingIntent
        PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
    )
    // 获取当前时间的Calendar实例,并设置小时和分钟
    val calendar = Calendar.getInstance().apply {
        set(Calendar.HOUR_OF_DAY, hour)
        set(Calendar.MINUTE, minute)
        set(Calendar.SECOND, 0)
    }
    // 设置闹钟,使用RTC_WAKEUP类型,在指定时间唤醒设备并执行pendingIntent
    alarmManager.setExact(
        AlarmManager.RTC_WAKEUP,
        calendar.timeInMillis,
        pendingIntent
    )
}

class AlarmReceiver : BroadcastReceiver() {
    // 重写BroadcastReceiver的onReceive方法,当接收到广播时调用
    override fun onReceive(context: Context, intent: Intent) {
        // 播放系统铃声
        AlarmStateManager.activateAlarm() // 激活状态并播放铃声

    }
}
复制代码
AndroidManifest.xml文件如下:
复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">



    <!-- 声明应用需要使用精确闹钟的权限 -->
    <uses-permission android:name="android.permission.USE_EXACT_ALARM" />


    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyClock"
        tools:targetApi="31">

        <!-- 定义一个接收器(Receiver)组件 -->
        <!--
            android:name=".AlarmReceiver"
            - 指定接收器的类名为 AlarmReceiver,这里的 "." 表示当前包名下的类。
            - AlarmReceiver 是一个继承自 BroadcastReceiver 的类,用于接收和处理广播消息。
         -->
        <receiver android:name=".AlarmReceiver" />

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.MyClock">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
相关推荐
孬甭_几秒前
C++ vector
开发语言·c++
AOwhisky25 分钟前
Python 学习笔记(第五期)——组合数据类型:列表、元组、集合与字典精讲——核心知识点自测与详解
开发语言·笔记·python·学习·云计算
灯澜忆梦9 小时前
GO_并发编程---定时器
开发语言·后端·golang
-银雾鸢尾-10 小时前
C#中的StringBuilder相关方法
开发语言·c#
-银雾鸢尾-10 小时前
C#中结构体与类的区别;抽象类与接口的区别
开发语言·c#
大模型码小白11 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
HLC++13 小时前
Linux的进程间通信
android·linux·服务器
段一凡-华北理工大学13 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
Ljwuhe13 小时前
C++——多态
开发语言·c++
心平气和量大福大14 小时前
C#-WPF-Window主窗体
开发语言·c#·wpf