用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>
相关推荐
2603_965148116 小时前
如何解析JSON数据?API返回的商品信息处理教程
开发语言·数据库·python·自动化·json·api
知无不研9 小时前
lambda表达式的使用(3)
开发语言·c++·lambda
cfm_29149 小时前
SpringAI + Ollama 本地大模型
java·开发语言·人工智能·语言模型
C++ 老炮儿的技术栈10 小时前
基于Qt实现轻量化本地音乐播放器
开发语言·c++·qt·c·播放器·音乐
qq_4480111610 小时前
C语言中的柔性数组
c语言·开发语言·柔性数组
小白学大数据10 小时前
长周期爬虫的数据一致性:断点续爬 + 事务回滚保障采集质量
开发语言·爬虫·测试工具
阿pin11 小时前
Android随笔-kotlin withContext
android·kotlin·withcontext
zlinear数据采集卡11 小时前
D223上位机C#开发实战:从帧解析到波形显示的完整实现
开发语言·arm开发·嵌入式硬件·fpga开发·开源·c#
Poo_Chai11 小时前
QT emit信号后完整处理流程,包括槽函数响应流程
java·开发语言·数据库
瑞码空间11 小时前
Java 图形界面(GUI)完整知识点手册
java·开发语言·图形界面·swing