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

Android(Kotlin)应用连接本地MySQL数据库失败求助

Android Kotlin本地MySQL注册无响应问题排查与解决

我是Android应用开发新手,用Kotlin编写代码,现在要实现应用连接本地MySQL所在电脑的服务器,完成用户注册数据提交和登录功能,但点击注册按钮完全没反应。已有网站能正常连接该本地服务器和数据库,以下是相关代码:

Dbhelper.kt

package com.example.myapplication

import java.sql.Connection
import java.sql.DriverManager
import java.sql.ResultSet
import java.sql.SQLException

class Dbhelper(private val url: String, private val user: String, private val password: String) {
    init {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver")
        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        }
    }

    fun connect(): Connection? {
        try {
            return DriverManager.getConnection(url, user, password)
        } catch (e: SQLException) {
            e.printStackTrace()
        }
        return null
    }

    fun isUserExists(login: String, email: String): Boolean {
        connect()?.use { connection ->
            val query = "SELECT * FROM appmovie_users WHERE login = ? OR email = ?"
            val preparedStatement = connection.prepareStatement(query)
            preparedStatement.setString(1, login)
            preparedStatement.setString(2, email)
            val resultSet: ResultSet = preparedStatement.executeQuery()
            return resultSet.next()
        }
        return false
    }

    fun addUser(login: String, email: String, password: String): Boolean {
        connect()?.use { connection ->
            val query = "INSERT INTO appmovie_users (login, email, password) VALUES (?, ?, ?)"
            val preparedStatement = connection.prepareStatement(query)
            preparedStatement.setString(1, login)
            preparedStatement.setString(2, email)
            preparedStatement.setString(3, password)
            val rowsAffected = preparedStatement.executeUpdate()
            return rowsAffected > 0
        }
        return false
    }
}

RegistrationActivity.kt

package com.example.myapplication 
                                                          
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.lifecycle.ViewModelProvider

class RegistrationActivity : AppCompatActivity() {

    private lateinit var viewModel: RegistrationViewModel

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

        val userLogin = findViewById<EditText>(R.id.user_login)
        val userEmail = findViewById<EditText>(R.id.user_email)
        val userPass = findViewById<EditText>(R.id.user_pass)
        val button = findViewById<Button>(R.id.button_reg)
        val linkToAuth = findViewById<TextView>(R.id.link_to_auth)
        val logoName = findViewById<TextView>(R.id.logoName)

        val dbUrl = "jdbc:mysql://localhost:3306/database-users-movieapp"
        val dbUser = "root"
        val dbPassword = ""

        val dbHelper = Dbhelper(dbUrl, dbUser, dbPassword)

        viewModel = ViewModelProvider(this)[RegistrationViewModel::class.java]

        button.setOnClickListener {
            val login = userLogin.text.toString().trim()
            val email = userEmail.text.toString().trim()
            val pass = userPass.text.toString().trim()

            if (login == "" || email == "" || pass == "") {
                Toast.makeText(this, "Not all fields are filled", Toast.LENGTH_LONG).show()
            } else {
                if (dbHelper.isUserExists(login, email)) {
                    Toast.makeText(this, "User with the same login or email already exists", Toast.LENGTH_LONG).show()
                } else {
                    viewModel.registerUser(login, email, pass)
                }
            }
        }
    }
}

RegistrationViewModel.kt

package com.example.myapplication

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

class RegistrationViewModel : ViewModel() {
    private val DB_URL = "jdbc:mysql://localhost:3306/database-users-movieapp"
    private val DB_USER = "root"
    private val DB_PASSWORD = ""

    private val databaseHelper = Dbhelper(DB_URL, DB_USER, DB_PASSWORD)

    val registrationResult = MutableLiveData<Boolean>()

    fun registerUser(login: String, email: String, password: String) {
        viewModelScope.launch(Dispatchers.IO) {
            val isRegistrationSuccessful = databaseHelper.addUser(login, email, password)
            registrationResult.postValue(isRegistrationSuccessful)
        }
    }
}

问题排查与解决方案

1. 主线程执行耗时操作导致阻塞

isUserExists方法直接在主线程调用数据库连接和查询,Android禁止主线程执行耗时操作,会触发ANR(应用无响应),导致按钮点击后无反馈。

解决:
将用户存在性检查移到协程中执行:

// 修改RegistrationActivity的按钮点击事件
button.setOnClickListener {
    val login = userLogin.text.toString().trim()
    val email = userEmail.text.toString().trim()
    val pass = userPass.text.toString().trim()

    if (login.isEmpty() || email.isEmpty() || pass.isEmpty()) {
        Toast.makeText(this, "请填写所有字段", Toast.LENGTH_LONG).show()
    } else {
        lifecycleScope.launch(Dispatchers.IO) {
            val exists = dbHelper.isUserExists(login, email)
            launch(Dispatchers.Main) {
                if (exists) {
                    Toast.makeText(this@RegistrationActivity, "该登录名或邮箱已存在", Toast.LENGTH_LONG).show()
                } else {
                    viewModel.registerUser(login, email, pass)
                }
            }
        }
    }
}

需确保Activity依赖协程库,并添加导入:import kotlinx.coroutines.launch、import kotlinx.coroutines.Dispatchers。

2. 本地MySQL连接地址错误

Android设备/模拟器的localhost指向自身,而非运行MySQL的电脑。需替换为电脑的本地IP地址(如192.168.xxx.xxx),同时确保MySQL允许远程连接、防火墙开放3306端口。

修改连接URL:

// 替换为你的电脑本地IP,添加必要参数
val dbUrl = "jdbc:mysql://192.168.1.100:3306/database-users-movieapp?useSSL=false&serverTimezone=UTC"

3. 未监听注册结果反馈

ViewModel的registrationResult已发送注册状态,但Activity未监听,导致成功/失败都无提示,看起来像无响应。

添加结果监听:
在RegistrationActivity的onCreate方法中添加:

viewModel.registrationResult.observe(this) { success ->
    if (success) {
        Toast.makeText(this, "注册成功", Toast.LENGTH_LONG).show()
        // 可跳转至登录页面
    } else {
        Toast.makeText(this, "注册失败,请重试", Toast.LENGTH_LONG).show()
    }
}

4. 额外安全提示

当前代码直接存储明文密码,存在安全风险,建议使用SHA-256或BCrypt加密后再存入数据库。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:50:01