mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 15:56:48 +08:00
fix(projects): parallelize project indexing with coroutines
This commit is contained in:
@@ -90,7 +90,7 @@ dependencies {
|
||||
implementation(libs.common.utilcode)
|
||||
implementation(libs.common.glide)
|
||||
implementation(libs.common.jsoup)
|
||||
implementation(libs.common.kotlin.coroutines)
|
||||
implementation(libs.common.kotlin.coroutines.android)
|
||||
|
||||
implementation(libs.google.auto.service.annotations)
|
||||
implementation(libs.google.gson)
|
||||
|
||||
@@ -39,7 +39,7 @@ common-javaparser = { module = "com.github.javaparser:javaparser-symbol-solver-c
|
||||
common-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.13.0" }
|
||||
common-io = { module = "commons-io:commons-io", version = "2.13.0" }
|
||||
common-kotlin = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
|
||||
common-kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlin-coroutines" }
|
||||
common-kotlin-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlin-coroutines" }
|
||||
common-jkotlin = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
|
||||
common-eventbus_ap = { module = "org.greenrobot:eventbus-annotation-processor", version = "3.3.1" }
|
||||
common-javapoet = { module = "com.squareup:javapoet", version = "1.13.0" }
|
||||
|
||||
@@ -48,3 +48,21 @@ constructor(
|
||||
lastLap = System.currentTimeMillis()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the given action with a stopwatch to log the time the action took to execute.
|
||||
*
|
||||
* @see StopWatch
|
||||
*/
|
||||
inline fun <R> withStopWatch(
|
||||
label: String,
|
||||
start: Long = System.currentTimeMillis(),
|
||||
lastLap: Long = start,
|
||||
action: (StopWatch) -> R
|
||||
): R {
|
||||
return StopWatch(label, start, lastLap).run {
|
||||
action(this).also {
|
||||
log()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ dependencies {
|
||||
implementation(projects.subprojects.xmlUtils)
|
||||
|
||||
implementation(libs.common.io)
|
||||
implementation(libs.common.kotlin.coroutines.android)
|
||||
implementation(libs.google.auto.service.annotations)
|
||||
implementation(libs.google.guava)
|
||||
|
||||
|
||||
+28
-7
@@ -42,6 +42,15 @@ import com.itsaky.androidide.tooling.api.models.BuildVariantInfo
|
||||
import com.itsaky.androidide.utils.DocumentUtils
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
import com.itsaky.androidide.utils.flashError
|
||||
import com.itsaky.androidide.utils.withStopWatch
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
@@ -88,20 +97,32 @@ class ProjectManagerImpl : IProjectManager, EventReceiver {
|
||||
|
||||
override fun setupProject(project: IProject) {
|
||||
this.rootProject = ProjectTransformer().transform(CachingProject(project))
|
||||
if (this.rootProject == null) {
|
||||
return
|
||||
}
|
||||
val rootProject = this.rootProject ?: return
|
||||
|
||||
// build variants must be updated before the sources and classpaths are indexed
|
||||
updateBuildVariants { buildVariants ->
|
||||
androidBuildVariants = buildVariants
|
||||
}
|
||||
|
||||
this.rootProject!!.subProjects.filterIsInstance(ModuleProject::class.java).forEach {
|
||||
it.indexSourcesAndClasspaths()
|
||||
if (it is AndroidModule) {
|
||||
it.readResources()
|
||||
withStopWatch("Setup project") {
|
||||
val indexerScope = CoroutineScope(Dispatchers.Default)
|
||||
val modulesFlow = flow {
|
||||
rootProject.subProjects.filterIsInstance(ModuleProject::class.java).forEach {
|
||||
emit(it)
|
||||
}
|
||||
}
|
||||
|
||||
val jobs = modulesFlow.map { module ->
|
||||
indexerScope.async {
|
||||
module.indexSourcesAndClasspaths()
|
||||
if (module is AndroidModule) {
|
||||
module.readResources()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// wait for the indexing to finish
|
||||
runBlocking { jobs.toList().awaitAll() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+26
-15
@@ -37,11 +37,20 @@ import com.itsaky.androidide.tooling.api.models.BasicAndroidVariantMetadata
|
||||
import com.itsaky.androidide.tooling.api.models.GradleTask
|
||||
import com.itsaky.androidide.tooling.api.util.findPackageName
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
import com.itsaky.androidide.utils.withStopWatch
|
||||
import com.itsaky.androidide.xml.resources.ResourceTableRegistry
|
||||
import com.itsaky.androidide.xml.versions.ApiVersions
|
||||
import com.itsaky.androidide.xml.versions.ApiVersionsRegistry
|
||||
import com.itsaky.androidide.xml.widgets.WidgetTable
|
||||
import com.itsaky.androidide.xml.widgets.WidgetTableRegistry
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import java.io.File
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
@@ -244,25 +253,27 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
|
||||
* Reads the resource files are creates the [com.android.aaptcompiler.ResourceTable] instances for
|
||||
* the corresponding resource directories.
|
||||
*/
|
||||
fun readResources() {
|
||||
suspend fun readResources() {
|
||||
// Read resources in parallel
|
||||
val threads = mutableListOf<Thread>()
|
||||
threads.add(
|
||||
Thread {
|
||||
getFrameworkResourceTable()
|
||||
getResourceTable()
|
||||
getDependencyResourceTables()
|
||||
withStopWatch("Read resources for module : $path") {
|
||||
val resourceReaderScope = CoroutineScope(
|
||||
Dispatchers.IO + CoroutineName("ResourceReader($path)"))
|
||||
|
||||
val resourceFlow = flow {
|
||||
emit(getFrameworkResourceTable())
|
||||
emit(getResourceTable())
|
||||
emit(getDependencyResourceTables())
|
||||
emit(getApiVersions())
|
||||
emit(getWidgetTable())
|
||||
}
|
||||
)
|
||||
threads.add(Thread(this::getApiVersions))
|
||||
threads.add(Thread(this::getWidgetTable))
|
||||
|
||||
for (thread in threads) {
|
||||
thread.start()
|
||||
}
|
||||
val jobs = resourceFlow.map { result ->
|
||||
resourceReaderScope.async {
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
for (thread in threads) {
|
||||
thread.join()
|
||||
jobs.toList().awaitAll()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user