上一篇我們有提到用 KAPT 參數去呼叫 純 Kotlin 和 Android 的 code generator ,這篇要延續這個主題,繼續來講一下會怎麼樣去呼叫它們來產生程式碼。
我們在 annotation processor 裡面有定義了 process
的方法:
@SupportedOptions("debug")
@AutoService(Processor::class)
class RssAnnotationProcessor : AbstractProcessor() {
// 略
override fun process(typeElementSet: MutableSet<out TypeElement>?, roundEnvironment: RoundEnvironment?): Boolean {
val logger = Logger(processingEnv.messager)
val isPureKotlinParser = processingEnv.options[KAPT_OPTION_KEY]?.toBoolean() ?: false
if (isPureKotlinParser) {
generateClassesForKotlin(logger, roundEnvironment)
} else {
generateClassesForAndroid(logger, roundEnvironment)
}
return true
}
// 略
}
其中的 generateClassesForKotlin
是產生 Kotlin 的 extension 和 parser 的地方。
private fun generateClassesForKotlin(logger: Logger, roundEnvironment: RoundEnvironment?) {
if (!isExtensionGenerated) {
KotlinExtensionGenerator(logger).generate().writeTo(processingEnv.filer)
isExtensionGenerated = true
}
generateParsers(roundEnvironment) { isRoot, element ->
logger.log("[RssAnnotationProcessor][generateClassesForKotlin] isRoot = $isRoot, element = $element")
KotlinParserGenerator(
element = element,
isRoot = isRoot,
logger = logger
).generate().writeTo(processingEnv.filer)
}
}
generateClassesForAndroid
則是負責產生 Android 的 extension 和 parser 。
private fun generateClassesForAndroid(logger: Logger, roundEnvironment: RoundEnvironment?) {
// This 'process' method could be called multiple times, so we use a flag to prevent it generate multiple times.
if (!isExtensionGenerated) {
AndroidExtensionGenerator(logger).generate().writeTo(processingEnv.filer)
isExtensionGenerated = true
}
generateParsers(roundEnvironment) { isRoot, element ->
AndroidParserGenerator(
element = element,
isRoot = isRoot,
logger = logger
).generate().writeTo(processingEnv.filer)
if (isRoot) {
AndroidReaderParserGenerator(
rootClassName = element.simpleName.toString(),
rootClassPackage = element.getPackage(),
logger
).generate().writeTo(processingEnv.filer)
}
}
}
因為 process
方法在 annotation processor 裡面會被呼叫多次,每當有類別的 annotation 被掃到,就會被呼叫一次,每次都是不同的 generation cycle ,被產生的 class 也會被放在不同的檔案裏面。
Android 的部分比較特殊的地方是它有產生自己的 reader ,它跟 parser 的不同在於它是使用產生後的 parser 去做其他的處理,像是資料快取和取得網路的 RSS 檔案來源,等於是把 parser 再包一層好用的 API ,這樣在 Android 上面可以更簡單地被使用。資料快取的部分,android 會用 database 以 url 當成是 key 去把資料存起來,也有設置過期時間,這樣可以確保不會抓到過期的資訊,也讓快取可以發揮作用。當然,外部 API 還是要按照自己的需求設計,也可以設計成讓使用者可以決定要不要使用快取。在取得網路 RSS 來源的部分,是使用了 OkHttp 直接去取得檔案內容。這些 Kotlin 和 Android 的 generator 會在後面的文章一一為各位講解。