PC パソコン

Android Studio「ClassNotFoundException」(ネストしたPreviewParameterProvider)の解決方法

Jetpack Compose Previewで、別クラスの内部に定義したPreviewParameterProviderを指定すると、レンダリング時にClassNotFoundExceptionが発生することがあります。GoogleはIssue #364917767として追跡し、Android Studio Rabbit 1 Canary 5で修正しました。

代表的なエラー

java.lang.ClassNotFoundException:
com.example.preview.PreviewData$SampleProvider

クラス名は異なります。Compose Previewだけが、外側のクラスと$で結ばれたネストProviderを読み込めないことが識別点です。

原因

修正前のCompose PreviewがネストしたProviderのソース名とバイナリ名を正しく解決できず、Preview用クラスローダーがクラスを発見できないIDE側の不具合です。

修正版:Android Studio Rabbit 1 Canary 5。公式情報は最初の発生版を確定していないため、特定の旧版すべてが影響を受けるとは断定できません。

発生条件・対象バージョン

  • @Previewと@PreviewParameterを使用する。
  • Providerが別のclassまたはobject内にネストされている。
  • アプリはビルドできてもDesign/SplitのPreviewが失敗する。
  • 修正前のAndroid Studioを使用している。

再現例

class PreviewData {
    class SampleProvider : PreviewParameterProvider<String> {
        override val values = sequenceOf("First", "Second")
    }
}

@Preview
@Composable
fun SamplePreview(
    @PreviewParameter(PreviewData.SampleProvider::class) value: String
) { Text(value) }

推奨する解決手順

  1. Preview詳細のClassNotFoundExceptionが、指定したProviderを指すことを確認する。
  2. Android Studio Rabbit 1 Canary 5以降の修正を含むビルドへ更新する。プレビュー版はStable版と並行導入して互換性を確認する。
  3. Gradle Sync後にBuild & Refreshを実行する。必要ならIDEを再起動する。
./gradlew clean assembleDebug

代替策

更新できない場合はProviderをトップレベルへ一時的に移します。

class SampleProvider : PreviewParameterProvider<String> {
    override val values = sequenceOf("First", "Second")
}

これは修正前IDEの名前解決を避ける回避策です。ネストProviderがCompose APIで禁止されているという意味ではありません。

確認方法

  1. 同じComposableを更新後のIDEで開く。
  2. 全Provider値のPreviewが描画されることを確認する。
  3. Preview詳細から例外が消えたことを確認する。
  4. Debugビルドと実機/エミュレーター実行も確認する。

注意点

トップレベルへ移しても失敗する場合は、Providerがabstractまたはinnerでないか、引数なしで生成できるか、values評価時に別の例外がないかを確認します。一般的な依存関係のClassNotFoundExceptionは別問題です。

まとめ

ネストしたPreviewParameterProviderだけがPreviewで見つからない場合はIssue #364917767に一致する可能性があります。Rabbit 1 Canary 5以降へ更新し、更新できない間はProviderをトップレベルへ移して確認してください。

参照した公式情報