AndroidStudioでMarkdownプレビューが表示されない時の対処法

プラグインは対応はしてるのに未だ表示されず。

👉 Markdown - IntelliJ IDEs Plugin | Marketplace hatena-bookmark

一時期は表示されてたことありませんでしたっけ。

 

■ プレビューを表示させる

これ。

The Java Chromium Embedded Framework (JCEF) is a simple framework for embedding Chromium-based browsers in other applications using the Java programming language.

👉 JetBrains/jcef: A simple framework for embedding Chromium-based browsers into Java-based applications. hatena-bookmark

AndroidStudio 稼働のための Java を JCEF が含まれているものに変更すればプレビューを表示できるようです。

[email protected] #19Jun 30, 2022 12:57PM
Based on #7

TLDR for https://intellij-support.jetbrains.com/hc/en-us/articles/206544879-Selecting-the-JDK-version-the-IDE-will-run-under:

In the Android Studio:

1. Find action (ctrl + shift + A / command + shift + A)
2. Search for Choose Boot Java Runtime for the IDE
3. Select the latest version in the "New:" dropdown - e.g. 11.0.12+7-b1504.27 JetBrains Runtime with JCEF
4. OK
5. Restart
Worked in: Android Studio Chipmunk | 2021.2.1 Patch 1 | Build #AI-212.5712.43.2112.8609683

👉 Regression in markdown support (crashes 100% of the time). Missing JCEF [159933628] - Visible to Public - Issue Tracker hatena-bookmark

リスタートすると正しく表示されました。

 

■ まとめ

[email protected] #20Jul 1, 2022 03:48AM
Why isn't it the default?

ほんとそう、なんか問題あるんでしょうか、未検証なのでしょうか?

ちなみに、Mermaid プラグインははっきり未対応のようです。

👉 Mermaid - IntelliJ IDEs Plugin | Marketplace hatena-bookmark


【Android】Gradle Version Catalog 関連のプラグインを探す

Gradle Version Catalog。

TOML ファイル作って使ってみました。

Android Studio でこんな。

⚠ This project uses Gradle Version Catalogs: this tool may not behave as expected.

なんか気持ちが悪いですよね。

update dependencies まわりがこれまで通りに正常に動いてるかどうか、心配になります。

そこらをチェックしてくれるツールを探します。

以下、人気順。


👉 ben-manes/gradle-versions-plugin: Gradle plugin to discover dependency updates hatena-bookmark


👉 jmfayard/refreshVersions: Life is too short to google for dependencies and versions hatena-bookmark


👉 littlerobots/version-catalog-update-plugin: Gradle plugin for updating a project version catalog hatena-bookmark

それぞれどこかで見かけたことがあると思います。

機能は、そのうち Android Studio にマージされるんだろうなと妄想。

👉 Jetpack Compose Samples でも使われている「Version catalog update plugin」で libs.versions.toml を書き出してみる hatena-bookmark
👉 「⚠ This project uses Gradle Version Catalogs: this tool may not behave as expected.」→ 今現在、Gradle Version Catalog には gradle-versions-plugin が必須では? hatena-bookmark


【Gradle Version Catalog】libs.versions.toml キー名の形式 camelCase vs kebab-case

一流のプログラマーのコードには、それぞれのこだわりや哲学があります。

Gradle Version Catalog で利用される設定ファイルの libs.versions.toml を眺めながら、気になったことがありました。

キー名の形式です。

Gradle Version Catalog

 

■ いろんな形式がある

Naming convention (programming)
👉 Naming convention (programming) - Wikipedia hatena-bookmark

 

■ TOML 的には

Case についてははっきりとしたきまりはないようです。

キーはベア・キー、クォート付きキー、ドット付きキーのいずれかです。
ベア・キーはASCII英数字とアンダースコア、ダッシュのみで構成されます(A-Za-z0-9_-)。 ASCII数字のみでも構いませんが、文字列として解釈されることに注意してください(例: 1234)。

👉キー TOML: 日本語 v1.0.0-rc.2 hatena-bookmark

こんなきまりもあります。

インライン・テーブルは一行で表現されるべきです。インライン・テーブルでは、配列と違って、最後の要素のあとにコンマを足すことはできません。波括弧の内側では改行は認められません。ただし、それぞれの値の中で改行することは、それぞれの値型で認められている範囲でできます。ですが、できるとしてもインライン・テーブルを複数行に分割することはなるべく避けるべきです。もしあなたがその必要があるように感じたのならば、普通のテーブルを用いるべきです。


name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
animal = { type.name = "pug" }

👉 インライン・テーブル TOML: 日本語 v1.0.0-rc.2 hatena-bookmark

 

■ GitHub で見てみる

camelCase


[libraries]
androidPlugin = { module = "com.android.tools.build:gradle", version = "4.2.2" }
robovmPlugin = { module = "com.mobidevelop.robovm:robovm-gradle-plugin", version.ref = "robovm" }
kotlinStdLib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlinCoroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.5.1" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }

👉 retrofit/libs.versions.toml at 5180f481c58b0be80ad81a0c1ec540fe7e91ee81 · square/retrofit hatena-bookmark

kebab-case


[libraries]
plugin-android = { module = "com.android.tools.build:gradle", version.ref = "plugin-android" }
plugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "plugin-kotlin" }
plugin-kotlin-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "plugin-kotlin" }
plugin-gver = { module = "com.github.ben-manes:gradle-versions-plugin", version.ref = "plugin-gver" }

👉 kmm-production-sample/libs.versions.toml at aed57893bab7e88a0df50285196e942be6934bf8 · Kotlin/kmm-production-sample hatena-bookmark
👉 PosterBox/libs.versions.toml at 9e988e7fb62620a6913493aeecc51cb71aba3595 · JakeWharton/PosterBox hatena-bookmark
👉 awesome-kotlin/libs.versions.toml at ae83263c467da6f81bb1abc7536ab6af7bc5b4d0 · KotlinBy/awesome-kotlin hatena-bookmark

camelCase - kebab-case


[libraries]
gradlePlugin-android = { module = "com.android.tools.build:gradle", version = "4.2.2" }
gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlinCompiler" }
gradlePlugin-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version = "1.6.20" }

👉 leakcanary/libs.versions.toml at f9462209ab553c76ad77673f7bebbd155fa76fa9 · square/leakcanary hatena-bookmark

その他


jsoup = { module = "org.jsoup:jsoup", version.ref = "1.15.3" }

でなく


jsoup = "org.jsoup:jsoup:1.15.3"

とも書ける。

👉 okhttp/libs.versions.toml at a94769c31ff18c5c768f790a92eab1de9b27fd83 · square/okhttp hatena-bookmark

あと、どこを選択するか、という問題もある。


com.google.firebase:firebase-bom
                    ^^^^^^^^^^^^

com.google.firebase:firebase-*
                    ^^^^^^^^^^

com.google.accompanist:accompanist-*
    ^^^^^^.^^^^^^^^^^^

com.google.accompanist:accompanist-imageloading-core
    ^^^^^^.^^^^^^^^^^^.            ^^^^^^^^^^^^^^^^^

com.google.accompanist:accompanist-glide
    ^^^^^^.^^^^^^^^^^^.            ^^^^^

com.google.android.libraries.places:places
    ^^^^^^.^^^^^^^.          ^^^^^^

com.google.maps.android:*
    ^^^^^^.     ^^^^^^^.^

com.google.maps.android:android-maps-utils
    ^^^^^^.     ^^^^^^^.        ^^^^^^^^^^

com.google.maps.android:maps-ktx
    ^^^^^^.     ^^^^^^^.^^^^^^^^

👉 refreshVersions/google-version-alias-rules.txt at main · jmfayard/refreshVersions hatena-bookmark

 

■ まとめ

「.(ドット)」に置き換えられて読み込まれる build,gradle 側の考慮も必要になります。

「重複しない直感的に分かりやすい名前」「kebab-case」にするのがスッキリしていいように思うけどみんなはどうしてますか?

👉 Jetpack Compose Samples でも使われている「Version catalog update plugin」で libs.versions.toml を書き出してみる hatena-bookmark
👉 Gradle Version Catalog への書き換えツールを作る【python】 hatena-bookmark
👉 「⚠ This project uses Gradle Version Catalogs: this tool may not behave as expected.」→ 今現在、Gradle Version Catalog には gradle-versions-plugin が必須では? hatena-bookmark


KMM や マルチプラットフォーム を見据えて SQLDelight で Repository

👉 Getting Started - Multiplatform - SQLDelight hatena-bookmark
👉 SQLDelight 1.x Quick Start Guide for Android – Handstand Sam hatena-bookmark

マルチプラットフォームに対応していますが、

まずは、Android のみで使ってみると良いです。

👉 Getting Started - Android - SQLDelight hatena-bookmark

Todo アプリ向けの Repository を作ります。

Hilt と Flow を使っています。

 

■ インストール

Gradleまわりは書き方いろいろですけども適宜書き換えてください。


buildscript {
  repositories {
    google()
    mavenCentral()
  }
  dependencies {
    classpath 'com.squareup.sqldelight:gradle-plugin:1.5.3'
  }
}

apply plugin: 'com.squareup.sqldelight'

// android driver
implementation "com.squareup.sqldelight:android-driver:1.5.3"

// flow-coroutine extension 
implementation "com.squareup.sqldelight:coroutines-extensions:1.5.3"

 

■ スキーマ / クエリー

パッケージ名を、com.your.package としています。


-- app/src/main/sqldelight/com/your/package/data/Todo.sq

CREATE TABLE todo (
  id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
  text TEXT NOT NULL,
  updated INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
);

INSERT INTO todo(text) VALUES ('宿題をする');
INSERT INTO todo(text) VALUES ('マンガを読む');
INSERT INTO todo(text) VALUES ('プールに行く');

selectAll:
SELECT * FROM todo ORDER BY updated DESC;

deleteAll:
DELETE FROM todo;

insert:
INSERT INTO todo (text) VALUES (:text);

update:
UPDATE todo SET text = :text, updated = (strftime('%s', 'now')) WHERE id = :entryId;

delete:
DELETE FROM todo
WHERE id = :entryId;

count:
SELECT COUNT(id) FROM todo;

Todo.sq ファイルをテキストで作成して、テーブル定義、実行クエリーとメソッド名を箇条書きします。

配置位置は、上記コメントの位置が自然で分かりやすいと思います。

この場合、SQLDelight によって以下に実装に利用するクラス群が生成されます。


app/build/generated/sqldelight/code/Database/debug/com/your/package/

 

■ Database Module

SQLDelightによって生成された Database クラスを利用して書きます。

今回は Android向けなので、AndroidSqliteDriver を使っています。


@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {

  @Provides
  @Singleton
  fun provideDatabase(@ApplicationContext context: Context): Database {
    val driver = AndroidSqliteDriver(Database.Schema, context, DB_NAME)
    return Database(driver)
  }

  private const val DB_NAME = "database.db"
}

JetpackCompose の UI である Screen-level の Composable はマルチに稼働しているので、 @Singleton としておくことを忘れてはなりません。

 

■ Repository

時間のかかる処理は Flow を使っておきます。


class TodoRepository @Inject constructor(
  private val database: Database
) {

  fun load(): Flow<List<Todo>> {
    return database.todoQueries.selectAll().asFlow().mapToList(Dispatchers.IO)
  }

  fun count(): Flow<Long> {
    return database.todoQueries.count().asFlow().mapToOne(Dispatchers.IO)
  }

  fun insert(text: String) {
    database.todoQueries.insert(text)
  }

  fun update(id: Long, text: String) {
    database.todoQueries.update(text, id)
  }

  fun delete(id: Long) {
    database.todoQueries.delete(id)
  }

}

Flow - Couroutine Extension は非常に便利です。


fun load(): Flow<List<Todo>> {
  return database.todoQueries.selectAll().asFlow().mapToList(Dispatchers.IO)
}

Cold な Flow で単発の List<Todo> の emit ではなく、データベースが変更されるたびに、新しい List<Todo> を emit してくれます。


@JvmName("toFlow")
fun <T : Any> Query<T>.asFlow(): Flow<Query<T>> = flow {
  val channel = Channel<Unit>(CONFLATED)
  channel.trySend(Unit)

  val listener = object : Query.Listener {
    override fun queryResultsChanged() {
      channel.trySend(Unit)
    }
  }

  addListener(listener)
  try {
    for (item in channel) {
      emit(this@asFlow)
    }
  } finally {
    removeListener(listener)
  }
}

👉 sqldelight/FlowExtensions.kt at master · cashapp/sqldelight hatena-bookmark

(更新中...)

👉 Jetpack Compose で Todo アプリを作ってみた - Qiita hatena-bookmark


3つの画像読み込みライブラリ Glide / Picasso / Coil - JetpackCompose 対応の状況

どれが、今、旬なのか。

まずはリンクを列挙しておきます。

全部使ってみようと思います。

giide vs picasso vs coil

👉 android glide, android picasso, android coil - 調べる - Google トレンド hatena-bookmark

 

Glide


32.8k stars
Watchers 1.1k watching
Forks 6k forks

👉 bumptech/glide: An image loading and caching library for Android focused on smooth scrolling hatena-bookmark

Glide

👉 Glide v4 : Fast and efficient image loading for Android hatena-bookmark

@sjudd Hey, I believe you're one of the maintainers of Glide. Is it a planned feature? Does Glide's team want help from the community on this? Jetpack Compose is going to stable soon, I believe later this month or next month

👉 Jetpack Compose Support · Issue #4459 · bumptech/glide hatena-bookmark

 

Picasso


18.3k stars
Watchers 867 watching
Forks 4k forks

👉 square/picasso: A powerful image downloading and caching library for Android hatena-bookmark

Picasso

👉 Picasso hatena-bookmark

Nobody works on Picasso. If you want something in the next N years definitely use Coil. Or Glide. Or whatever. They're all fine.

Image loading is a terrible, horrible business to be in. It's been really nice not being in that business for the last few years. I don't see a reason to resume. I certainly have no intent to support it anymore. Picasso accomplished its goal of moving the ecosystem out of the painful image loaders of 2011/2012 to the fluent and extensible ones we know today. But it's filled with technical debt and the legacy of poor design (at least, in hindsight) and is currently very, very stuck between a major refactor and redesign with no end in sight.

👉 Consider providing Jetpack Compose support · Issue #2203 · square/picasso hatena-bookmark

 

Coil


8.4k stars
Watchers 98 watching
Forks 512 forks

👉 coil-kt/coil: Image loading for Android backed by Kotlin Coroutines. hatena-bookmark

Coil

👉 Coil hatena-bookmark

To add support for Jetpack Compose, import the extension library:

implementation("io.coil-kt:coil-compose:2.1.0")

👉 Jetpack Compose - Coil hatena-bookmark

 

まとめ

JetpackCompose への対応ライブラリ群も見逃せません。

👉 skydoves/landscapist: 🍂 Jetpack Compose image loading library that fetches and displays network images with Glide, Coil, and Fresco hatena-bookmark

👉 wasabeef/composable-images: The Composable Images is a library providing Jetpack Compose wrapper for Glide, Picasso, and Coil. hatena-bookmark

アーキテクチャー、フレームワーク、ライブラリの選定はそのプロダクトの安定感に直結します。

機能確認を中心に検証しながら、将来の本筋を外してはなりません。

👉 画像読み込みライブラリ「COIL」 hatena-bookmark