用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>
相关推荐
香精煎鱼香翅捞饭6 分钟前
java通用自研接口限流组件
java·开发语言
-凌凌漆-15 分钟前
【C#】async与await介绍
开发语言·c#
小猿_0025 分钟前
C语言单链表头插法
c语言·开发语言
Hello.Reader35 分钟前
在 Rust 中实现面向对象的状态模式
开发语言·rust·状态模式
JouJz37 分钟前
Java虚拟机之垃圾收集(一)
java·开发语言·jvm
ljx14000525501 小时前
Android AudioFlinger(一)——初识AndroidAudio Flinger
android
ljx14000525501 小时前
Android AudioFlinger(四)—— 揭开PlaybackThread面纱
android
Codingwiz_Joy1 小时前
Day04 模拟原生开发app过程 Androidstudio+逍遥模拟器
android·安全·web安全·安全性测试
叶羽西1 小时前
Android15 Camera框架中的StatusTracker
android·camera框架
梦中千秋1 小时前
安卓设备root检测与隐藏手段
android