Launcher2分析-加载和绑定AllApp列表

本文详细分析了Android Launcher2中如何加载和绑定AllApp列表的过程,从launcher.xml布局到核心视图AppsCustomizePagedView,再到LoaderTask的loadAndBindApps方法和AllAppsList的实现。探讨了ApplicationInfo的创建以及Launcher作为LauncherModel Callback的角色,重点在于理解应用列表的加载逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上篇关联博客:Launcher2分析-加载Workspace数据和绑定

Android应用列表的视图就在launcher.xml中,也就是说应用列表视图一开始就已经加载好了,只是没有显示出来,属性为invisible,它是和Workspace在同一个viewgroup中。id为apps_customize_pane,实际类型为com.android.launcher2.AppsCustomizeTabHost,继承自TabHost,而layout  apps_customize_pane.xml中包含了一个id为apps_customize_pane_content,类型为AppsCustomizePagedView的child,改类型间接继承了PagedView,是应用列表的核心view。

<include layout="@layout/apps_customize_pane"
            android:id="@+id/apps_customize_pane"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="invisible" />

从LauncherModel$LoaderTask#loadAndBindApps()开始分析:

private void loadAndBindAllApps() {
            if (DEBUG_LOADERS) {
                Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);
            }
            if (!mAllAppsLoaded) {//判断是否所有app都加载过了
                loadAllAppsByBatch();//加载所有app信息并且分批绑定
                synchronized (LoaderTask.this) {
                    if (mStopped) {
                        return;
                    }
                    mAllAppsLoaded = true;
                }
            } else {
                onlyBindAllApps();//跳过加载过程,直接绑定
            }
        }

分析loadAllAppsByBatch():

private void loadAllAppsByBatch() {
            final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;

            // Don't use these two variables in any of the callback runnables.
            // Otherwise we hold a reference to them.
            final Callbacks oldCallbacks = mCallbacks.get();
            if (oldCallbacks == null) {
                // This launcher has exited and nobody bothered to tell us.  Just bail.
                Log.w(TAG, "LoaderTask running with no launcher (loadAllAppsByBatch)");
                return;
            }

            final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);//需要action为main的
            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);//还需要category为launcher的
//跟linux多用户有关,有多少个用户,就有多少个UserHandle,但是手机一般来说就一个吧
            final List<UserHandle> profiles = mUserManager.getUserProfiles();

            mBgAllAppsList.clear();
            final int profileCount = profiles.size();
            for (int p = 0; p < profileCount; p++) {
                UserHandle user = profiles.get(p);
                List<LauncherActivityInfo> apps = null;
                int N = Integer.MAX_VALUE;//这个只是初始化指,后面会改变

                int startIndex;
                int i = 0;
                int batchSize = -1;
                while (i < N && !mStopped) {//N为apps的size
                    if (i == 0) {
                        final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
                        apps = mLauncherApps.getActivityList(null, user);//获取对应用户的所有app
                        if (DEBUG_LOADERS) {
                            Log.d(TAG, "queryIntentActivities took "
                                    + (SystemClock.uptimeMillis()-qiaTime) + "ms");
                        }
                        if (apps == null) {
                            return;
                        }
                        N = apps.size();//在这里重新赋值给N,而不会是Integer的max value
                        if (DEBUG_LOADERS) {
                            Log.d(TAG, "queryIntentActivities got " + N + " apps");
                        }
                        if (N == 0) {
                            // There are no apps?!?
                            return;
                        }
                        if (mBatchSize == 0) {
                            batchSize = N;
                        } else {
                            batchSize = mBatchSize;//设置怎么分批,一批有多少个应用。应该是太多一批可能会导致anr,导致其他事件无法被及时响应
                        }

                        final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
                        Collections.sort(apps,
                                new LauncherModel.ShortcutNameComparator(mLabelCache));//将apps重排序
                        if (DEBUG_LOADERS) {
                            Log.d(TAG, "sort took "
                                    + (SystemClock.uptimeMillis()-sortTime) + "ms");
                        }
                    }

                    final long t2 = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;

                    startIndex = i;
                    for (int j=0; i<N && j<batchSize; j++) {//在外围的while循环作用下,for里面的内容会循环N次
                        // This builds the icon bitmaps.
                        mBgAllAppsList.add(new ApplicationInfo(apps.get(i), user,
                                mIconCache, mLabelCache));//mBgAllAppsList不是一个List,而是一个封装了List的类,后面会分析这里
                        i++;
                    }

                    final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                    final ArrayList<ApplicationInfo> added = mBgAllAppsList.added;//将added引用个对象发出去
                    final boolean firstProfile = p == 0;
                    mBgAllAppsList.added = new ArrayList<ApplicationInfo>();//将added成员指向新的对象,因为这次是新增,那么下次就不是了
                    mHandler.post(new Runnable() {
                        public void run() {
                            final long t = SystemClock.uptimeMillis();
                            if (callbacks != null) {
                                if (firstProfile) {//firstProfile应该代表的是root用户,需要加加载所有app
                                    callbacks.bindAllApplications(added);//后面会重点分析这个方法
                                } else {
                                    callbacks.bindAppsAdded(added);//如果是其他用户,则只加载新增内容
                                }
                                if (DEBUG_LOADERS) {
                                    Log.d(TAG, "bound " + added.size() + " apps in "
                                        + (SystemClock.uptimeMillis() - t) + "ms");
                                }
                            } else {
                                Log.i(TAG, "not binding apps: no Launcher activity");
                            }
                        }
                    });

                    if (DEBUG_LOADERS) {
                        Log.d(TAG, "batch of " + (i-startIndex) + " icons processed in "
                                + (SystemClock.uptimeMillis()-t2) + "ms");
                    }

                    if (mAllAppsLoadDelay > 0 && i < N) {
                        try {
                            if (DEBUG_LOADERS) {
                                Log.d(TAG, "sleeping for " + mAllAppsLoadDelay + "ms");
                            }
                            Thread.sleep(mAllAppsLoadDelay);//每批app的绑定任务交到主线程的队列中后,要休眠一段时间再向队列放入下一批任务
                        } catch (InterruptedException exc) { }
                    }
                }

                if (DEBUG_LOADERS) {
                    Log.d(TAG, "cached all " + N + " apps in "
                            + (SystemClock.uptimeMillis()-t) + "ms"
                            + (mAllAppsLoadDelay > 0 ? " (including delay)" : ""));
                }
            }
        }

分析一下mBgAllAppsList.add(new ApplicationInfo(apps.get(i), user, mIconCache, mLabelCache));其中mBgAllAppsList是AllAppsList类型,其中add方法的源码如下:

public void add(ApplicationInfo info) {
        if (findActivity(data, info.componentName, info.user)) {//当对应用户已经存在这个component时,就不会添加到data和added中
            return;
        }
        data.add(info);//添加到data,存放所有app
        added.add(info);//添加到added,存放相对于上次加载来说为新增的app
    }

Launcher实现了LauncherModel的Callback,下面分析Launcher#bindAllApplications()

public void bindAllApplications(final ArrayList<ApplicationInfo> apps) {
        Runnable setAllAppsRunnable = new Runnable() {
            public void run() {
                if (mAppsCustomizeContent != null) {

//这个mAppsCustomizeContent就是一开始说的AppsCustomizePagedView类型对象,调用setApps方法后,就会去重绘这个view了。

 mAppsCustomizeContent.setApps(apps); } } }; 
// Remove the progress bar entirely; we could also make it GONE 
// but better to remove it since we know it's not going to be used 
View progressBar = mAppsCustomizeTabHost. findViewById(R.id.apps_customize_progress_bar); 
if (progressBar != null) { 
((ViewGroup)progressBar.getParent()).removeView(progressBar); 
// We just post the call to setApps so the user sees the progress bar 
// disappear-- otherwise, it just looks like the progress bar froze 
// which doesn't look great 
mAppsCustomizeTabHost.post(setAllAppsRunnable);//会在progressbar消失后再post到消息队列中 
} else { 
// If we did not initialize the spinner in onCreate, then we can directly set the 
// list of applications without waiting for any progress bars views to be hidden. 
setAllAppsRunnable.run(); }
 }


<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demo66</artifactId> <version>1.0-SNAPSHOT</version> <name>demo66</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <junit.version>5.10.2</junit.version> </properties> <dependencies> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-controls</artifactId> <version>17.0.6</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-fxml</artifactId> <version>17.0.6</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-web</artifactId> <version>17.0.6</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-swing</artifactId> <version>17.0.6</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-media</artifactId> <version>17.0.6</version> </dependency> <dependency> <groupId>org.controlsfx</groupId> <artifactId>controlsfx</artifactId> <version>11.2.1</version> </dependency> <dependency> <groupId>com.dlsc.formsfx</groupId> <artifactId>formsfx-core</artifactId> <version>11.6.0</version> <exclusions> <exclusion> <groupId>org.openjfx</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>net.synedra</groupId> <artifactId>validatorfx</artifactId> <version>0.5.0</version> <exclusions> <exclusion> <groupId>org.openjfx</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.kordamp.ikonli</groupId> <artifactId>ikonli-javafx</artifactId> <version>12.3.1</version> </dependency> <dependency> <groupId>org.kordamp.bootstrapfx</groupId> <artifactId>bootstrapfx-core</artifactId> <version>0.4.0</version> </dependency> <dependency> <groupId>eu.hansolo</groupId> <artifactId>tilesfx</artifactId> <version>21.0.3</version> <exclusions> <exclusion> <groupId>org.openjfx</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.github.almasb</groupId> <artifactId>fxgl</artifactId> <version>17.3</version> <exclusions> <exclusion> <groupId>org.openjfx</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.13.0</version> <configuration> <source>24</source> <target>24</target> </configuration> </plugin> <plugin> <groupId>org.openjfx</groupId> <artifactId>javafx-maven-plugin</artifactId> <version>0.0.8</version> <executions> <execution> <!-- Default configuration for running with: mvn clean javafx:run --> <id>default-cli</id> <configuration> <mainClass>com.example.demo66/com.example.demo66.HelloApplication</mainClass> <launcher>app</launcher> <jlinkZipName>app</jlinkZipName> <jlinkImageName>app</jlinkImageName> <noManPages>true</noManPages> <stripDebug>true</stripDebug> <noHeaderFiles>true</noHeaderFiles> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>这是我POM。xml之前的代码,我要怎么修改
最新发布
06-16
<think>根据您提供的pom.xml文件,您需要添加MySQLConnector/J9.2.0的依赖。同时,由于您使用的是Java24(根据maven-compiler-plugin配置),请注意MySQLConnector/J9.2.0要求的最低Java版本是8,所以兼容性没有问题。###修改步骤1.**添加MySQLConnector/J9.2.0依赖**:在`<dependencies>`部分添加以下依赖项:```xml<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>9.2.0</version></dependency>```2.**确保模块化支持**:在`module-info.java`中,我们已经讨论过需要添加`requirescom.mysql.cj;`驱动服务提供者声明。3.**解决可能存在的依赖冲突**:由于您已经排除了多个依赖中的JavaFX模块,MySQL驱动不包含JavaFX,所以无需额外排除。###修改后的pom.xml(仅显示修改部分)```xml<dependencies><!--已有的依赖...--><!--添加MySQL驱动--><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>9.2.0</version></dependency><!--其他依赖保持不变--></dependencies>```###完整pom.xml(整合后)```xml<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>demo66</artifactId><version>1.0-SNAPSHOT</version><name>demo66</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><junit.version>5.10.2</junit.version></properties><dependencies><!--JavaFX依赖--><dependency><groupId>org.openjfx</groupId><artifactId>javafx-controls</artifactId><version>17.0.6</version></dependency><dependency><groupId>org.openjfx</groupId><artifactId>javafx-fxml</artifactId><version>17.0.6</version></dependency><dependency><groupId>org.openjfx</groupId><artifactId>javafx-web</artifactId><version>17.0.6</version></dependency><dependency><groupId>org.openjfx</groupId><artifactId>javafx-swing</artifactId><version>17.0.6</version></dependency><dependency><groupId>org.openjfx</groupId><artifactId>javafx-media</artifactId><version>17.0.6</version></dependency><!--第三方库--><dependency><groupId>org.controlsfx</groupId><artifactId>controlsfx</artifactId><version>11.2.1</version></dependency><dependency><groupId>com.dlsc.formsfx</groupId><artifactId>formsfx-core</artifactId><version>11.6.0</version><exclusions><exclusion><groupId>org.openjfx</groupId><artifactId>*</artifactId></exclusion></exclusions></dependency><dependency><groupId>net.synedra</groupId><artifactId>validatorfx</artifactId><version>0.5.0</version><exclusions><exclusion><groupId>org.openjfx</groupId><artifactId>*</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.kordamp.ikonli</groupId><artifactId>ikonli-javafx</artifactId><version>12.3.1</version></dependency><dependency>极客时间<groupId>org.kordamp.bootstrapfx</groupId><artifactId>bootstrapfx-core</artifactId><version>0.4.0</version></dependency><dependency><groupId>eu.hansolo</groupId><artifactId>tilesfx</artifactId><version>21.0.3</version><exclusions><exclusion><groupId>org.openjfx</groupId><artifactId>*</artifactId></exclusion></exclusions></dependency><dependency><groupId>com.github.almasb</groupId><artifactId>fxgl</artifactId><version>17.3</version><exclusions><exclusion><groupId>极客时间org.openjfx</groupId><artifactId>*</artifactId></exclusion></exclusions></dependency><!--MySQLConnector/J9.2.0--><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>9.2.0</version></dependency><!--测试依赖--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>${junit.version}</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>${junit.version}</version><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.13.0</version><configuration><source>24</source><target>24</target></configuration></plugin><plugin><groupId>org.openjfx</groupId><artifactId>javafx-maven-plugin</artifactId><version>0.0.8</version><executions><execution><id>default-cli</id><configuration><mainClass>com.example.demo66/com.example.demo66.HelloApplication</mainClass><launcher>app</launcher><jlinkZipName>app</jlinkZipName><jlinkImageName>app</jlinkImageName><noManPages>true</noManPages><stripDebug>true</stripDebug><noHeaderFiles>true</noHeaderFiles></configuration></execution></executions></plugin></plugins></build></project>```###验证依赖是否正确添加在命令行中运行:```bashmvndependency:tree```检查输出中是否包含:```[INFO]+-com.mysql:mysql-connector-j:jar:9.2.0:compile```###模块信息文件(`module-info.java`)确保您的`module-info.java`包含以下内容:```javamodulecom.example.demo66{requiresjavafx.controls;requiresjavafx.fxml;requiresjavafx.web;requiresjava.sql;requirescom.mysql.cj;//关键:MySQL9.2.0模块名//其他requires...requiresorg.controlsfx.controls;//...其他第三方库的requiresopenscom.example.demo66tojavafx.fxml;exportscom.example.demo66;//如果使用数据库实体类,开放给JavaFX绑定openscom.example.demo66.modeltojavafx.base;//声明驱动服务providesjava.sql.Driverwithcom.mysql.cj.jdbc.Driver;}```###注意事项1.**Java版本兼容性**:您使用的是Java24,但MySQLConnector/J9.2.0是为Java8+设计的,应该兼容。2.**模块系统**:确保所有依赖项都支持模块系统,或者您可能需要为某些库使用自动模块名。3.**运行配置**:如果使用IDE运行,确保运行配置的VM选项中包含:```--add-modulescom.mysql.cj```###§§相关问题§§:1.如何解决Maven依赖冲突?2.Java模块化项目中如何处理非模块化JAR?3.使用JavaFX时如何设计数据库访问层?4.如何配置Maven打包包含所有依赖的可执行JAR?</think>根据您的 `pom.xml` 文件,您需要添加 MySQL Connector/J 9.2.0 依赖并解决可能的依赖冲突。以下是完整的修改方案: ### 修改后的 `pom.xml` 文件 ```xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demo66</artifactId> <version>1.0-SNAPSHOT</version> <name>demo66</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <junit.version>5.10.2</junit.version> <!-- 添加MySQL驱动版本属性 --> <mysql.connector.version>9.2.0</mysql.connector.version> </properties> <dependencies> <!-- JavaFX 依赖 --> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-controls</artifactId> <version>17.0.6</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-fxml</artifactId> <version>17.0.6</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-web</artifactId> <version>17.0.6</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-swing</artifactId> <version>17.0.6</version> </dependency> <dependency> <groupId>极客时间 org.openjfx</groupId> <artifactId>javafx-media</artifactId> <version>17.0.6</version> </dependency> <!-- 第三方库 --> <dependency> <groupId>org.controlsfx</groupId> <artifactId>controlsfx</artifactId> <version>11.2.1</version> </dependency> <dependency> <groupId>com.dlsc.formsfx</groupId> <artifactId>formsfx-core</artifactId> <version>11.6.0</version> <exclusions> <exclusion> <groupId>org.openjfx</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>net.synedra</groupId> <artifactId>validatorfx</artifactId> <version>0.5.0</version> <exclusions> <exclusion> <groupId>org.openjfx</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.kordamp.ikonli</groupId> <artifactId>ikonli-javafx</artifactId> <version>12.3.1</version> </dependency> <dependency> <groupId>org.kordamp.bootstrapfx</groupId> <artifactId>bootstrapfx-core</artifactId> <version>0.4.0</version> </dependency> <dependency> <groupId>eu.hansolo</groupId> <artifactId>tilesfx</artifactId> <version>21.0.3</version> <exclusions> <exclusion> <groupId>org.openjfx</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.github.almasb</groupId> <artifactId>fxgl</artifactId> <version>17.3</version> <exclusions> <exclusion> <groupId>org.openjfx</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> <!-- 添加 MySQL Connector/J 9.2.0 依赖 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>${mysql.connector.version}</version> </dependency> <!-- 测试依赖 --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.13.0</version> <configuration> <source>24</source> <target>24</target> <!-- 添加编译器参数 --> <compilerArgs> <arg>--add-modules</arg> <arg>javafx.controls,javafx.fxml,com.mysql.cj</arg> </compilerArgs> </configuration> </plugin> <plugin> <groupId>org.openjfx</groupId> <artifactId>javafx-maven-plugin</artifactId> <version>0.0.8</version> <executions> <execution> <id>default-cli</id> <configuration> <mainClass>com.example.demo66/com.example.demo66.HelloApplication</mainClass> <launcher>app</launcher> <jlinkZipName>app</jlinkZipName> <jlinkImageName>app</jlinkImageName> <noManPages>true</noManPages> <stripDebug>true</stripDebug> <noHeaderFiles>true</noHeaderFiles> <!-- 添加运行参数 --> <options> <option>--add-modules=com.mysql.cj</option> <option>--add-exports=java.sql/com.mysql.cj.jdbc=ALL-UNNAMED</option> </options> </configuration> </execution> </executions> </plugin> </plugins> </build> </project> ``` ### 关键修改说明 1. **添加 MySQL 驱动依赖**: ```xml <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>9.2.0</version> </dependency> ``` 2. **添加编译器参数**: ```xml <compilerArgs> <arg>--add-modules</arg> <arg>javafx.controls,javafx.fxml,com.mysql.cj</arg> </compilerArgs> ``` 3. **配置运行时模块**: ```xml <options> <option>--add-modules=com.mysql.cj</option> <option>--add-exports=java.sql/com.mysql.cj.jdbc=ALL-UNNAMED</option> </options> ``` ### 完整的 `module-info.java` 配置 ```java module com.example.demo66 { requires javafx.controls; requires javafx.fxml; requires javafx.web; requires java.sql; // MySQL 9.2.0 模块名 requires com.mysql.cj; requires org.controlsfx.controls; requires com.dlsc.formsfx; requires net.synedra.validatorfx; requires org.kordamp.ikonli.javafx; requires org.kordamp.bootstrapfx.core; requires eu.hansolo.tilesfx; requires com.almasb.fxgl.all; opens com.example.demo66 to javafx.fxml; exports com.example.demo66; // 开放模型包访问权限 opens com.example.demo66.model to javafx.base; // 添加服务提供者声明 provides java.sql.Driver with com.mysql.cj.jdbc.Driver; } ``` ### 验证配置的步骤 1. **刷新 Maven 依赖**: ```bash mvn clean install ``` 2. **检查依赖树**: ```bash mvn dependency:tree | grep mysql ``` 应该输出:`[INFO] +- com.mysql:mysql-connector-j:jar:9.2.0:compile` 3. **验证模块配置**: 在 IntelliJ IDEA 中: - 右键点击项目 → Maven → Reimport - 检查 Project Structure (File → Project Structure) - 在 Modules → Dependencies 中应看到 `mysql-connector-j-9.2.0.jar` - 在 Libraries 中应看到 MySQL 驱动 ### 常见问题解决方案 **问题:仍然找不到模块** 1. 检查驱动版本: ```bash mvn dependency:list | grep mysql ``` 2. 手动添加模块依赖: ```java requires static com.mysql.cj; ``` 3. 在运行配置中添加 VM 参数: ``` --add-modules=com.mysql.cj --add-exports=java.sql/com.mysql.cj.jdbc=ALL-UNNAMED ``` **问题:驱动服务未注册** 在 `module-info.java` 中添加: ```java uses java.sql.Driver; provides java.sql.Driver with com.mysql.cj.jdbc.Driver; ``` ### 数据库连接测试类 ```java package com.example.demo66; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DatabaseTest { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC"; String user = "root"; String password = "yourpassword"; try (Connection conn = DriverManager.getConnection(url, user, password)) { System.out.println("成功连接到MySQL数据库!"); System.out.println("数据库版本: " + conn.getMetaData().getDatabaseProductVersion()); } catch (SQLException e) { System.err.println("数据库连接失败:"); e.printStackTrace(); // 检查驱动是否加载 try { Class.forName("com.mysql.cj.jdbc.Driver"); System.out.println("MySQL驱动已加载"); } catch (ClassNotFoundException ex) { System.err.println("找不到MySQL驱动类"); ex.printStackTrace(); } } } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值