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
相关产品推荐
相关产品推荐

