You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin实现无邮件APP发送邮件时页面崩溃求助

解决NetworkOnMainThreadException并实现自动邮件发送

问题根源

android.os.NetworkOnMainThreadException 是因为你在UI主线程中执行了邮件发送的网络操作。Android系统禁止主线程处理耗时网络请求,避免UI卡顿甚至无响应。

解决方案:用Kotlin协程将网络操作移到后台线程

Kotlin协程是Android官方推荐的异步处理方案,语法简洁且易于维护,完美适配你的需求。

1. 添加协程依赖

确保你的build.gradle(Module level)中包含协程核心与Android扩展库:

dependencies {
    // 协程核心库
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3"
    // Android协程扩展(用于主线程调度)
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
}

2. 重构邮件发送逻辑

把邮件发送的核心代码封装成一个suspend函数(挂起函数),让它能在协程中执行:

import javax.mail.*
import javax.mail.internet.InternetAddress
import javax.mail.internet.MimeMessage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

// 封装邮件发送逻辑的挂起函数
suspend fun sendEmail(userInput: String, autoGeneratedDateTime: String): Boolean {
    return withContext(Dispatchers.IO) { // 指定在IO线程执行网络操作
        try {
            // 替换为你的邮箱配置(账号、密码、SMTP服务器等)
            val props = Properties().apply {
                put("mail.smtp.host", "smtp.your-email-provider.com")
                put("mail.smtp.port", "587")
                put("mail.smtp.auth", "true")
                put("mail.smtp.starttls.enable", "true")
            }

            val session = Session.getInstance(props, object : Authenticator() {
                override fun getPasswordAuthentication(): PasswordAuthentication {
                    return PasswordAuthentication("your-email@example.com", "your-app-password")
                }
            })

            // 构建邮件内容,结合用户输入和自动生成的日期时间
            val message = MimeMessage(session).apply {
                setFrom(InternetAddress("your-email@example.com"))
                addRecipient(Message.RecipientType.TO, InternetAddress("recipient@example.com"))
                subject = "自动发送的邮件 - $autoGeneratedDateTime"
                text = "用户输入内容:$userInput\n发送时间:$autoGeneratedDateTime"
            }

            Transport.send(message)
            true // 发送成功返回true
        } catch (e: Exception) {
            e.printStackTrace()
            false // 发送失败返回false
        }
    }
}

3. 在按钮点击事件中启动协程

在你的Activity/Fragment中,处理发送按钮的点击事件,生成日期时间后调用上述挂起函数,并在主线程更新UI状态:

import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.*

class EmailSendActivity : AppCompatActivity() {
    private lateinit var userInputEt: EditText
    private lateinit var sendBtn: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_email_send)

        userInputEt = findViewById(R.id.user_input_et)
        sendBtn = findViewById(R.id.send_btn)

        sendBtn.setOnClickListener {
            val userInput = userInputEt.text.toString().trim()
            if (userInput.isEmpty()) {
                Toast.makeText(this, "请输入内容", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }

            // 自动生成当前日期时间
            val dateTimeFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
            val autoDateTime = dateTimeFormat.format(Date())

            // 启动协程执行邮件发送
            CoroutineScope(Dispatchers.Main).launch {
                // 显示加载状态(可选)
                sendBtn.isEnabled = false
                sendBtn.text = "发送中..."

                val sendSuccess = sendEmail(userInput, autoDateTime)

                // 回到主线程更新UI
                sendBtn.isEnabled = true
                sendBtn.text = "发送邮件"

                if (sendSuccess) {
                    Toast.makeText(this@EmailSendActivity, "邮件发送成功", Toast.LENGTH_SHORT).show()
                } else {
                    Toast.makeText(this@EmailSendActivity, "邮件发送失败,请检查配置", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }
}

4. 必要的权限配置

在AndroidManifest.xml中添加网络权限:

<uses-permission android:name="android.permission.INTERNET" />

<!-- 如果SMTP服务器使用明文HTTP(不推荐),需在application标签内添加此配置 -->
<application
    ...
    android:usesCleartextTraffic="true">
    ...
</application>

关键注意事项

  • 邮箱授权:使用Gmail等主流邮箱时,需开启应用专用密码(而非登录密码),否则会被安全拦截。
  • 异常处理:务必捕获邮件发送过程中的所有异常(如网络错误、认证失败等),避免应用崩溃。
  • 生命周期管理:如果在Fragment中使用协程,建议用viewModelScope替代CoroutineScope(Dispatchers.Main),防止内存泄漏。

内容的提问来源于stack exchange,提问作者are_flour

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 18:32:53