Android Studio连接MySQL失败,添加网络权限后应用崩溃求助
问题分析与解决方案
核心崩溃原因
你的代码存在几个关键问题,导致应用崩溃:
- 主线程执行网络IO:即使通过
StrictMode临时放宽限制,Android高版本(尤其是API 28+)对主线程网络操作的管控依然严格,这不仅会引发崩溃,还会导致ANR(应用无响应)。 - 可能缺失MySQL JDBC驱动依赖:Android SDK默认不包含MySQL的JDBC驱动,若未在项目中引入依赖,会触发
ClassNotFoundException导致崩溃。 - 未正确关闭数据库资源:
Connection、Statement、ResultSet使用后未关闭,会造成资源泄漏,长期运行引发异常。 - SQL注入风险:直接拼接字符串构建SQL语句,存在严重安全隐患,同时可能因特殊字符导致SQL语法错误。
分步修复方案
1. 引入MySQL JDBC驱动依赖
在项目的build.gradle(Module level)的dependencies块中添加驱动依赖:
dependencies { // 其他依赖... implementation 'mysql:mysql-connector-java:8.0.33' }
注意:如果是Android Studio Arctic Fox及以上版本,需在
settings.gradle中确保添加mavenCentral仓库:dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() // 必须添加此行 } }
2. 移除非主线程执行网络操作
使用后台线程执行数据库操作,避免阻塞主线程。推荐使用Coroutine(现代Android开发方式)或AsyncTask(兼容旧版本):
方案一:使用Coroutine(推荐)
先确保项目引入Coroutine依赖:
dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4' }
修改MainActivity代码:
package com.database.myapplication; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.PreparedStatement; import kotlinx.coroutines.CoroutineScope; import kotlinx.coroutines.Dispatchers; import kotlinx.coroutines.MainScope; import kotlinx.coroutines.launch; public class MainActivity extends AppCompatActivity implements CoroutineScope by MainScope() { private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = findViewById(R.id.denemetext); // IO线程执行数据库操作,主线程更新UI launch(Dispatchers.IO) { String result = testDB("onur"); launch(Dispatchers.Main) { tv.setText(result); } } } private String testDB(String name) { Connection con = null; PreparedStatement st = null; ResultSet rs = null; try { // MySQL 8.0+驱动类名已变更 Class.forName("com.mysql.cj.jdbc.Driver"); con = DriverManager.getConnection( "jdbc:mysql://192.168.56.1:3306/giris_sistemi?useSSL=false&serverTimezone=UTC", "onur", "12345"); String result = "Database connection success\n"; // 使用PreparedStatement防止SQL注入 String sql = "select * from kisiler where kisi_name like ?"; st = con.prepareStatement(sql); st.setString(1, "%" + name + "%"); // 模糊查询需添加% rs = st.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData(); while(rs.next()) { result += rsmd.getColumnName(1) + ": " + rs.getString(1) + "\n"; result += rsmd.getColumnName(2) + ": " + rs.getInt(2) + "\n"; result += rsmd.getColumnName(3) + ": " + rs.getString(3) + "\n"; } return result; } catch(Exception e) { e.printStackTrace(); return e.toString(); } finally { // 关闭资源,避免泄漏 try { if(rs != null) rs.close(); if(st != null) st.close(); if(con != null) con.close(); } catch(Exception e) { e.printStackTrace(); } } } }
方案二:使用AsyncTask(兼容旧版本)
package com.database.myapplication; import androidx.appcompat.app.AppCompatActivity; import android.os.AsyncTask; import android.os.Bundle; import android.widget.TextView; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.PreparedStatement; public class MainActivity extends AppCompatActivity { private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = findViewById(R.id.denemetext); new DBTask().execute("onur"); } private class DBTask extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... params) { Connection con = null; PreparedStatement st = null; ResultSet rs = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); con = DriverManager.getConnection( "jdbc:mysql://192.168.56.1:3306/giris_sistemi?useSSL=false&serverTimezone=UTC", "onur", "12345"); String result = "Database connection success\n"; String sql = "select * from kisiler where kisi_name like ?"; st = con.prepareStatement(sql); st.setString(1, "%" + params[0] + "%"); rs = st.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData(); while(rs.next()) { result += rsmd.getColumnName(1) + ": " + rs.getString(1) + "\n"; result += rsmd.getColumnName(2) + ": " + rs.getInt(2) + "\n"; result += rsmd.getColumnName(3) + ": " + rs.getString(3) + "\n"; } return result; } catch(Exception e) { e.printStackTrace(); return e.toString(); } finally { try { if(rs != null) rs.close(); if(st != null) st.close(); if(con != null) con.close(); } catch(Exception e) { e.printStackTrace(); } } } @Override protected void onPostExecute(String result) { tv.setText(result); } } }
3. 精简Manifest配置
移除不必要的权限(你的代码无需定位、电话等权限),精简后的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.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <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.MyApplication" tools:targetApi="31"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
4. 额外注意事项
- MySQL版本兼容:MySQL 8.0+需使用
com.mysql.cj.jdbc.Driver驱动类,且URL需添加serverTimezone参数(如serverTimezone=UTC)。 - 网络可达性:确保测试设备与MySQL服务器在同一局域网,且服务器允许外部连接(修改MySQL配置的
bind-address为0.0.0.0,并授权远程访问权限)。 - 生产环境建议:Android应用直接用JDBC连接MySQL并非最佳实践,推荐通过后端API(如Spring Boot、Node.js)中转数据库操作,提升安全性与性能。
内容的提问来源于stack exchange,提问作者user20113308
相关产品推荐
相关产品推荐

