用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>
相关推荐
oliveira-time1 小时前
Java 1.8(也称为Java 8)
java·开发语言
钰爱&5 小时前
【Linux】POSIX 线程信号量与互斥锁▲
java·开发语言·jvm
yt948326 小时前
Matlab实现绘制任意自由曲线
开发语言·matlab
oioihoii8 小时前
C++23 std::generator:用于范围的同步协程生成器 (P2502R2, P2787R0)
开发语言·c++·c++23
免檒8 小时前
go基于redis+jwt进行用户认证和权限控制
开发语言·redis·golang
没有梦想的咸鱼185-1037-16638 小时前
全球森林数据如何分析?基于R语言森林生态系统结构、功能与稳定性分析与可视化
开发语言·随机森林·数据分析·r语言
Your易元8 小时前
设计模式-迭代器模式
java·开发语言
2401_858286118 小时前
CD37.【C++ Dev】string类的模拟实现(上)
开发语言·c++·算法
╭⌒心岛初晴8 小时前
JAVA练习题(2) 找素数
java·开发语言·算法·java练习题·判断素数/质数
四谷夕雨8 小时前
C++八股 —— vector底层
开发语言·c++