Android Auto を学ぶその1 とにかく表示してみる

Android Auto を学びたいな〜と思って勉強してみることにしました。

概要

Android で自動車にてアプリを動かす仕組みは2つあります。一つは Android Auto、もう一つが Android Automotive。

Android Auto はスマートフォンで動くアプリを車のナビ画面に投影するイメージ。ナビ側が Android Auto をサポートしている必要があります。動作にはスマートフォンが必要で、純粋な車用アプリというよりも、スマフォ用アプリに車用画面を用意してあげる、という形になります。

Android Automotive は、車のナビに Android OS が組み込まれている場合に利用できます。スマートフォンを必要とせず、車の画面のみでアプリをインストールできます。この機能を積んでいる車は2022/09/26現在市場にまだ全然ないはずで、おそらくボルボとポルシェの一部にしか存在していないと思います。日本車に至っては1台も存在しない気がします。

自分の持っている車(Mazda3)は Android Automotive を使うことができないので、Android Auto にまとを絞って学んでいきます。なお、Android Auto が前提のアプリは避けるべきであるため、基本的には車に接続しなくとも単体で動くアプリ + 車用画面があるアプリとするべきですが、ここではとりあえず Android Auto の画面だけに絞っています。

ホストについて

Android Auto 対応車で作成したアプリを動かすとき、アプリは車と直接やりとりする訳ではありません。このときの接続先はスマフォに入っている Android Auto アプリです。Android Auto アプリはホストと呼ばれ、全ての Auto 対応アプリはこのホストとやりとりします。もし Android Automotive 対応の車で動かす場合は車載器に OS が入っているので、Android Automotive がホストになります。

developer.android.com このドキュメントに、ホストとは何かが記載されています。

ホストは、ライブラリの API によって提供される、アプリを車で実行するための機能を実装するバックエンド コンポーネントです。ホストは、アプリの検出とそのライフサイクルの管理、モデルのビューへの変換、ユーザー操作のアプリへの通知にいたるまで、幅広い役割を担います。モバイル デバイスでは、このホストは Android Auto によって実装されます。

API Level について

Android Auto には API Level という概念が存在しています。これはどの機能までを利用可能かを示すものです。ホストのバージョンに左右されます。現在利用可能なのは API Level 5です。これを動かすには Android Auto 8.1 以降のアプリが端末にインストールされている必要があります。

個人的に重要と考えているのは API Level 3 で追加された API です。これがあると CarHardwareManager を利用できます。CarHardwareManager を使うことができれば、車のコンピュータから吐き出される速度、燃料残量、ジャイロ、位置情報、ETCカードの状態などを取得することが可能になるのです。絶対取得したいですよね!!それぞれの API Level で何ができるかはリリースノートを参照することでわかります。

developer.android.com

とりあえず文字列を表示してみる

まずは簡単な表示を、簡単なコードで試してみるのが良さそうです。早速コードを書いてみることにします。まずは何を書く必要があるのかをみてみましょう。

  • gradle に Android Auto の依存を追加する
  • AndroidManifest.xmlAndroid Auto に必要な記述を追加する
  • automotiveApp を記載した xml リソースを作成する
  • androidx.car.app.CarAppService クラスを実装する
  • androidx.car.app.CarAppService から起動される androidx.car.app.Session を実装する
  • androidx.car.app.Session から呼ばれる androidx.car.app.Screen を実装する

gradle に Android Auto の依存を追加する

app/build.gradle に、以下の依存を追加します。

dependencies {
    implementation "androidx.car.app:app:1.3.0-beta01"
    implementation "androidx.car.app:app-projected:1.3.0-beta01"
}

2022/11/07時点の最新版は 1.3.0-beta01 であり、これを試すのであれば API Level 5 の機能が利用可能になります。端末に最新の Android Auto アプリをインストールしておきましょう(8.1 以降でないと API 呼び出しでクラッシュします)。 余談ですが1.3.0系がでた当初、Android Auto は 8.1 より前のバージョンしかストアにありませんでした。そのため 1.3.0 を利用するには Android Auto アプリのテスターになってより新しいバージョンを得る必要があったのかなと思います。ですがテスター募集はもう締め切られているので、SDK はあるが動かせない状態になっていました。

AndroidManifest.xmlAndroid Auto に必要な記述を追加する

まずは既存の application 内にエントリポイントとなる service クラスの記述を追加しましょう。

<service
            android:name=".SampleAndroidAutoAppService"
            android:exported="true">
            <intent-filter>
                <action android:name="androidx.car.app.CarAppService"/>
            </intent-filter>
        </service>

次に、最低限必要な CarApiLevel 、及びテンプレートを利用する旨を宣言しましょう。automotive_app_desc ファイルは次で作成します。

<application>
...
        <meta-data
            android:name="androidx.car.app.minCarApiLevel"
            android:value="1"
            tools:ignore="MetadataTagInsideApplicationTag" />
        <meta-data
            android:name="com.google.android.gms.car.application"
            android:resource="@xml/automotive_app_desc"/>
</application>

automotiveApp を記載した xml リソースを作成する

automotive_app_desc.xml を作成しましょう。今回のアプリでは、情報を表示するためにテンプレートと言うものを使うことになります。この時、<automotiveApp> 内に利用する旨を宣言する必要があります。

<?xml version="1.0" encoding="utf-8"?>
<automotiveApp>
  <uses name="template" />
</automotiveApp>

もしsmsを利用するアプリを作りたい場合、ここに <uses name="sms" /> を、またメディアアプリを作りたい場合、<uses name="media"/> を宣言することになります。

androidx.car.app.CarAppService クラスを実装する

Android Auto では、Activity ではなく Service が起動されます。そして車向けアプリ用として Service を拡張した CarAppService が用意されているので、これを継承する形になります。

developer.android.com

class SampleAndroidAutoAppService : CarAppService() {
    override fun createHostValidator(): HostValidator {
        return if (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) {
            HostValidator.ALLOW_ALL_HOSTS_VALIDATOR
        } else {
            HostValidator.Builder(applicationContext)
                .addAllowedHosts(R.array.hosts_allowlist_sample)
                .build()
        }
    }

    override fun onCreateSession(): Session {
        return SampleAndroidAutoAppSession()
    }
}

createHostValidator は、接続しているホストをチェックするものです。何をチェックしたいのでしょうか?今回の場合、Android Auto アプリからの呼び出しかどうかをチェックしているのです。

今回のコードの場合、デバッグ中は HostValidator.ALLOW_ALL_HOSTS_VALIDATOR を返すことになります。この実態は空っぽの許可リストを持ち、全てを許可するフラグを ON にした HostValidator クラスのインスタンスです。

@NonNull
    public static final HostValidator ALLOW_ALL_HOSTS_VALIDATOR = new HostValidator(null,
            new HashMap<>(), true);

そうでない場合は else に入ることになります。ここでは、R.array.hosts_allowist_sample をビルダに渡していますが、この中身はどうなっているのでしょう?

    <string-array name="hosts_allowlist_sample" translatable="false">
        

        
        <item>fdb00c43dbde8b51cb312aa81d3b5fa17713adb94b28f598d77f8eb89daceedf,
            com.google.android.projection.gearhead</item>
        
        <item>70811a3eacfd2e83e18da9bfede52df16ce91f2e69a44d21f18ab66991130771,
            com.google.android.projection.gearhead</item>
        
        <item>1975b2f17177bc89a5dff31f9e64a6cae281a53dc1d1d59b1d147fe1c82afa00,
            com.google.android.projection.gearhead</item>

        
        <item>c241ffbc8e287c4e9a4ad19632ba1b1351ad361d5177b7d7b29859bd2b7fc631,
            com.google.android.apps.automotive.templates.host</item>
        
        <item>dd66deaf312d8daec7adbe85a218ecc8c64f3b152f9b5998d5b29300c2623f61,
            com.google.android.apps.automotive.templates.host</item>
        
        <item>50e603d333c6049a37bd751375d08f3bd0abebd33facd30bd17b64b89658b421,
            com.google.android.apps.automotive.templates.host</item>
    </string-array>

com.google.android.projection.gearhead とはなんでしょうか?その答えは Android Auto アプリのパッケージ名です。 https://play.google.com/store/apps/details?id=com.google.android.projection.gearhead&hl=ja&gl=US

試しに、DHU に接続すると com.google.android.projection.gearhead パッケージ名を検証している様子を窺い知ることができます。

androidx.car.app.CarAppService から起動される androidx.car.app.Session を実装する

Session を実装しましょう。Session は onCreateScreen に abstract メソッドがあるのですが、これを上書きして Screen を実装します。この Screen で、カーナビ画面に表示する画面を実装しますが、ここでは Screen を実装するクラスを別に分けることにします。

class SampleAndroidAutoAppSession : Session() {
    override fun onCreateScreen(intent: Intent): Screen {
        return SampleAndroidAutoAppScreen(carContext)
    }
}

Screen を実装するには carContext が必要です。これは Session がプロパティとして持っているのでそのまま渡せば良いです。

androidx.car.app.Session から呼ばれる androidx.car.app.Screen を実装する

クルマの画面に出す UI を実装しましょう!Android Auto では、自由に UI を作成するのは許されていません(とある技を使えばなんでも表示できますが、規約的に許されていません)。Template から選んで表示することになります。 developer.android.com

また、表示内容の更新回数にも厳しい制限があることに注意が必要です。Template によって異なりますが、今回書くコードの場合、6回表示内容を更新したらクラッシュします。 developer.android.com

class SampleAndroidAutoAppScreen(carContext: CarContext) : Screen(carContext) {
    override fun onGetTemplate(): Template {
        val carAppLevel = carContext.carAppApiLevel
        val row = Row.Builder().setTitle("carAppLevel: $carAppLevel").build()
        val pane = Pane.Builder().addRow(row).build()
        return PaneTemplate.Builder(pane)
            .setHeaderAction(Action.APP_ICON)
            .build()
    }
}

ここまでやれば、とりあえず実行して画面に表示できるはずです!次回は DHU(Desktop Head Unit) を使い、コンピュータの画面上で Android Auto をテストしてみましょう。

JetpackCompose にて、画面離脱時に非同期で何かする

画面を離脱するときに、何かしらの処理を行いたいことがあります。例えば画面を離脱するときに DB になんか記録するとか、API を叩いておく、とかです。アプリが動いている間にやってくれれば良い程度で、バックグラウンドに回った時のことは考えません。

画面離脱時をハンドリング

画面を離脱するときは DisposableEffect(Unit)onDispose でフックすると良さそうです。DisposableEffect はクリーンアップ処理が可能な副作用で、key に Unit を指定すれば「画面から離脱する時の処理ブロック」を実現できます。

@Composable
fun SampleScreen() {
...
    DisposableEffect(Unit) {
        onDispose {
   // ここで処理を書きたい 
        }
    }
...

developer.android.com

自分は基本的に ViewModel を利用しているので、ViewModel を用意して `recordData()` という関数を書いてみる事にします。

@HiltViewModel
class SampleScreenViewModel @Inject constructor() : ViewModel() {
...

  fun recordData() { 
       // データを保存する処理を書く予定
  }

...
}


fun SampleScreen() { 
...
  DisposableEffect(Unit) {
    onDispose {
      viewModel.recordData()
    }
  }
...

ViewModel に処理を書く

ViewModel の recordData() 関数を実装しましょう。メインスレッドを止めたくはないので、recordData() のなかで非同期に処理を実行させたいです。

@HiltViewModel
class SampleScreenViewModel @Inject constructor() : ViewModel() {
...

fun recordData() {
  viewModelScope.launch { 
     // データを保存する
   }
}

...
}

で、↑は間違いです。viewModelScope を使っているので、画面離脱時にこの ViewModel も破棄されるため、viewModelScope ではコルーチンの処理がキャンセルされてしまいます。


DB に書き込みするだけであれば、ひょっとするとうまく動くかもしれません。SQLite への書き込み処理が早いためです。もう少し時間のかかる処理の場合は ViewModel の破棄が走り、コルーチンはキャンセルされる事でしょう。


よって、このコンポーザブルが破棄されても動くことのできるより広いスコープを使う必要があります。手っ取り早くGlobalScope (デリケート扱いです)を使ってみましょう。

@HiltViewModel
class SampleViewModel @Inject constructor() : ViewModel() {
...

fun recordData() {
  GlobalScope.launch { 
     // データを保存する
   }
}

...
}

↑の例は動きますが、ハードコードしていて良くありません。ここの場合だと、テスト時に問題になる可能性があります。よって外から注入できるようにしておくと良いでしょう。

@HiltViewModel
class SampleViewModel @Inject constructor(private val externalScope: CoroutineScope = GlobalScope) : ViewModel() {
...

fun recordData() {
  externalScope.launch { 
      // データを保存する
   }
}

...
}

GlobalScope は先ほども書いた通りデリケート扱いですが、そこまで時間を占有しない処理で、処理をキャンセルする必要がなく、処理の生存期間がアプリケーション起動中とイコールな場合は利用しても良いと思います。
GlobalScope

または、withContext(NonCancellable) を使うという選択肢もありそうです。
https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable/

React のエンジニアが Jetpack Compose を勉強してみた

育休前は React と go をよく書いていましたが、育休が終わって Android の仕事につくことになったので、Jetpack Compose の勉強をしました。といっても自分ばズブの素人というわけではなく、Jetpack Compose が導入される前には Android のエンジニアで、確かマルチモジュールが世の中に出始めたかな〜ぐらいの時代で Web 方面に進んだので、そこらへんの時代で知識が止まっています。

Jetpack Compose とは

https://developer.android.com/jetpack/compose
Android ネイティブアプリケーションを、宣言的 UI でアプリを作ることができるキットです。これまで Android は Activity(いわばウィンドウ。一画面に必ず1つしかない) や Fragment(いわばウィンドウの上における、View の土台みたいなもの。1画面、つまり Activity 上に複数置くことができる) という上に、xml でレイアウトを指定(HTMLみたいな感じ)して、描画された View に対し、Activity や Fragment にコードを書いて View をバインドしたり、クリックイベントを記述したりしていました。

Jetpack Compose では、土台は Activity や Fragment ではあるものの、この2つはもっぱら Jetpack Compose のルート要素置き場として機能します。xml でレイアウトを書く手法は廃止され、表示用コードとロジックが合体しているような感覚です。ものすごく雑にいうと React みたいなやつです。

React の知識と照らし合わせて勉強

https://developer.android.com/courses/android-basics-compose/course
https://developer.android.com/courses/pathways/compose
ドキュメントやコードラボをやっていきました。コードラボでコードを書きながら、「これは React でいうこれなんだな」という突き合わせをしながら理解していきました。その上で Compose ならではの理解を深めていくと良いのかなと思っています。

React で言うコンポーネントは Composable な関数で表す

React で以下のように書くと、ファンネル勤怠 と書かれたテキストが表示されます。

 function Title() {
   return <div>ファンネル勤怠</div>;
 }

これを Android でやろうとするとこうなるわけです。

 @Composable
 fun Title() {
  Text(text = "ファンネル勤怠") 
 }

なんとなく、Web エンジニアでも親しみやすい感じになっているのではないでしょうか。やはり宣言的 UI というだけあって React によく似ています。React と違って Class でコンポーネントは作れず、全て関数で UI を作ります。またコンポーネントとは言わずコンポーザブル(composable)と言います。UIは、状態が変化したらコンポーズ(compose)され、その際にコンポーザブルな関数がひとしきり呼ばれ再描画される仕組みです。

もう一点、大きな違いがあります。それは描画する要素を戻り値として返す必要があるか、ないかという部分です。

今一度 React のコードを見てみると

 function Title() {
   return <div>ファンネル勤怠</div>;
 }

ReactElement を返しているのがわかります。つまり、UI は関数の最後でまとめて return する必要があります。

ところが Jetpack Compose の関数は返り値は Unit です。これは Typescript でいう Void に相当します。すなわち、UI を関数の最後で返す必要はなく、

 @Composable
 fun Title() {
  Text(text = "ファンネル勤怠")
  val mes = "xxxxx"
  Box {
    Text(text = "詳細")
    println(mes)
  }
  println(mes)
 }

こういった記述も可能なわけです。

Compose で最高に楽になったのはリストではないでしょうか。従来は RecyclerView という View クラスを実装することでリストを作っていました。これはAdapter とか ViewHolder とか登場人物が少し多く、細かなコードを書いてリスト中の item をどのように使い回すかを書く必要がありました。そうしないとスクロール時にパフォーマンスが悪化するからです。

Compose だとこのように書けます

    LazyColumn {
        items(items = items, key = { item -> item.id }) {
            WorkingTimesListItem(
                item = it,
                onClickDetail = onClickDetail
            )
        }
    }

key がついているのは React 経験者ならピンとくるものであると思います。ちなみに Kotlin は関数の引数で、一番うしろにあるラムダは、関数の引数ブロックを飛び出して、{ ... } ブロックを使って書くことが出来ます。 LazyColumn も、本来であれば LazyColumn(content: ここに Composable な関数を書く) となるのですが、言語機能によってこう書くことができるため、宣言的 UI としてネストしていったとしても読みやすい、親和性の高いものになっている気がします。

状態

全ては再コンポーズされるので、そのままだとコンポーズ関数内に状態を保持し続けることは出来ません。React では useState を使っていたりしますが、Compose にもにたものは用意されています。

 function XXX() {
 ...
   var isClicked by remember { mutableStateOf(false) }
   ...

こう宣言すれば、isClicked は再コンポーズ後でも失われないので、状態を保持できます。by は Property を委譲する Kotlin の言語機能です。Kotlin では、今回のように宣言した var の場合は 、デフォルトで setter と getter が生えるのですが、この setter と getter を自分で指定できます。

    var name: String = name
        set(value) {
            field  = value.toLowerCase().capitalize()
            updateCount++
        }

ここで by を使うと、setter と getter に使う関数(つまり、setter と getter を実装した関数)を指定できます。これによって、setter、getter のロジックを抽出し、テストしやすくしたり、再利用性を向上させるのですが、Compose はこの機能を利用して、簡単に状態を保持する事のできる remember を提供している、ということになります。そしてこの remember もコンポーザブルです。

ビジネスロジックを兼ね合わせた状態を考えた場合、ViewModel を利用することになります。https://developer.android.com/jetpack/compose/state#viewmodels-source-of-truth

詳細はこちら https://developer.android.com/jetpack/compose/state

副作用

複雑なアプリを作っていくとどうしても副作用を使わざるを得ないケースが出てきます。Compose は副作用もサポートしています。

useEffect と LaunchedEffect

例えばReact を思い返すと、useEffect があると思います。

 useEffect(() => {
   update();
 });

これに対応するものとして、LaunchedEffect があります。

 LaunchedEffect(Unit) {
 	update()
 }

どちらも再生成に伴いに副作用が走るものになっています。つまり、どちらもコンポーネント、Composable のライフサイクルに沿った形で副作用を行っているということになります。両者とも、新しい副作用を実行するときに、前回の副作用はキャンセルされます。

これを 特定の値が変更された場合のみ副作用を走らせようとする と、React では以下のようになります。例えば id が変わった場合にのみ update() を試みる場合。

 const [id, setId] = useState(defaultId);
 
 useEffect(() => {
   update(id)
 }, [id]);

Composable ではどうでしょうか?

 @Composable
 var id by remember { mutableStateOf(defaultId) }
 
 LaunchedEffect(id) {
 	update(id)
 }

LaunchedEffect 関数にわたす1つ目の引数は React の dependencies array と相似しています。両者とも id が変化しなければ、再生成されても再び実行されません。

LaunchedEffect にわたす関数はコルーチンスコープ内で実行されます。つまり API を叩いたりだとかで UI をブロックされることはありませんし、suspend 関数という非同期処理を呼ぶことが出来ます。

ところで、React では useEffect にはクリーンアップ関数をつけることが出来ます。

  
  useEffect(() => {
    subscribe()
    
    return function cleanup() {
    	  unsubscribe()
    }
  });

これは Compose においては DisposableEffect を使って表現できます。クリーンアップ関数をつけると言うよりも、クリーンアップ関数が必要な場合は DisposableEffect を使う、という感じです。

 DisposableEffect(Unit) {
         subscribe()
         onDispose {
             unsubscribe()
         }
     }

React でいう Context

React では、多層な階層で状態を伝達させていくとバケツリレーが大変であることから、context の利用を考えることがあります。https://ja.reactjs.org/docs/context.html

そこまで頻繁に利用するものでもない気がしますが、例えば react-hook-form なんか使うと体験することがあるのではないでしょうか。

似たものは Compose にも用意されていました。CompositionLocal です。
https://developer.android.com/jetpack/compose/compositionlocal
例では、デザインに使う色をトップの階層で決めたとしても、その色を遥か下の階層で使う場合はめっちゃバケツリレーが必要で不便です、バケツリレーしたくありません、というものです。

まだ自分では使ったことがありませんが、 自分はアプリのデザインをマテリアルデザインで統一する MaterialTheme object は触っており、色やら文字のサイズやらを様々な階層の Composable で触ることになるのですが、これにも CompositionLocal の実装が使われているみたいです。

ナビゲーション

自分が過去に関わったプロダクトでは、フロントエンドのナビゲーションには React を Next.js 上で動かし、そこで Router を使っています。Next.js では、というか Web には URL がありますので、各々の場所でURL を指定して遷移すると思います。 Composable ではナビゲーションを司る Composalbe NavHost が用意されているので、通常はそちらを利用します。

まず、遷移する Composable を全部 NavHost Composable で囲みます。ここで遷移する画面を登録するイメージです。

https://developer.android.com/jetpack/compose/navigation#create-navhost

 NavHost(navController = navController, startDestination = "profile") {
     composable(route = "profile") { Profile(navController = navController) }
     composable(route = "friendslist") { FriendsList(navController = navController) }
     /*...*/
 }

NavHost を親とし、Profile Composable や FriendList Composable を遷移名(route)と紐付けて置いておきます。遷移するときは、この遷移名を使い、NavController を使って遷移します。navController は NavHost から受け取ります。

 @Composable
 fun Profile(navController: NavController) {
     /*...*/
     Button(onClick = { navController.navigate("friendslist") }) {
         Text(text = "Navigate next")
     }
     /*...*/
 }

route で指定している文字列は、定数化したりして記述ミスを防ぐのが一般的なようです。

デザイン

React では、各 DOM に対して style props を指定するのが最も原始的な方法になります。

 <p style={backgroundColor:"red"}>Color</p>

同じアプローチは Composable にも用意されています。Modifier です。

 Text(
   text = "Color",
   modifier = Modifier.background(color = Color.Red)
 )

ただし、React で直接 style props を渡すのは、パフォーマンスの面でも、管理の面でもおすすめしかねるので、スタイルを別に定義し className でスタイル名を指定するのが一般的です。

 <p className="title">Color</p>

Composable の場合、デザインが自由自在な Web とは少し事情が異なります。というのも、Android というプラットフォームの上で動く以上、Android の世界観を反映したデザインにする必要性があるからです。この場合、テーマ機能を使ってデザインを統一するのが一般的なようです。

https://developer.android.com/jetpack/compose/themes/material

これは MaterialTheme Composalbe を使うことになると思います。全体にテーマを当てたいので、最もトップの階層で MaterialTheme Composable を置いて、その下に様々な Composable を置いていく感じです。以下の例では、isSystemInDarkTheme() を使って、ダークモード中であれば暗い色を指定するようにしています。

 val Teal200 = Color(0xFF03DAC5)
 
 val Indigo200 = Color(0xFF9FA8DA)
 val Indigo500 = Color(0xFF3F51B5)
 val Indigo700 = Color(0xFF303F9F)
 val BlueGray50 = Color(0xFFECEFF1)
 val BlueGray900 = Color(0xFF263238)
 
 private val DarkColorPalette = darkColors(
     primary = Indigo200,
     primaryVariant = Indigo700,
     secondary = Teal200,
     background = BlueGray900
 )
 
 private val LightColorPalette = lightColors(
     primary = Indigo500,
     primaryVariant = Indigo700,
     secondary = Teal200,
     background = BlueGray50
 )
 
 @Composable
 fun TryJetpackComposeTheme(
     darkTheme: Boolean = isSystemInDarkTheme(),
     content: @Composable () -> Unit
 ) {
     val colors = if (darkTheme) {
         DarkColorPalette
     } else {
         LightColorPalette
     }
 
     MaterialTheme(
         colors = colors,
         typography = Typography,
         shapes = Shapes,
         content = content
     )
 }
 
 @Composable
 fun TryJetpackComposeApp() {
     TryJetpackComposeTheme {
         val navController = rememberNavController()
         val items = listOf(Screen.Home.name, Screen.Stamp.name)
 
         Scaffold(...) {
   ....

従来では、色は colors.xml に記述していって、それを各地で使うのが一般的でしたが、今回からは変数で色を定義のが推奨されています。

所感

やっぱり宣言的 UI ということで React の知識と結びつけることができるものになっています。Android 固有のライフサイクルを意識する場面は圧倒的に少なくなり、React と同じようなライフサイクルを意識すれば良くなったのは嬉しいです。

コードを書く量も削減されていて、昔のように Activity や Fragment を用意して、XML にレイアウトをかき、DataBinding で bind して、リストの場合は RecyclerView の諸々のコードを用意して...という手間が一挙に無くなったのが嬉しいです。カスタム View 的なものも作りやすくなりました。開発に時間がかかるのが Android のネックな部分だなあと思っていたのですが、その弱点がなくなった印象です。

また Google 公式でドキュメントやコードラボが充実しているため、確かな知識を素早くつけることができる点も魅力です。

ツーリングマップル

初めてツーリングマップルを買ったのは14年前。狂ったようにバイクを乗っていた時代。当時はバイク用のナビはおろかスマフォは存在すらなく、僕はお金もなかったのでケータイの使い放題プランにすら入っておらず、デジタルで自分の位置や地図を表示するすべはありませんでした。


そのためツーリングマップルをバイクに積載し、地図をある程度頭の中に入れつつ、案内板を見て目的地を目指していました。ツーリングマップルは観光案内にもなるスグレモノで、宿でメンバーみんなでツーリングマップルを見ながらワイワイとルート設定したのを覚えています。


そして時が経った現在。GoolgeMap が素晴らしくよくできていて、ツーリングマップルも散々見たということでかつて使っていたツーリングマップルは友人にあげてしまい、もう買うことはないかなと思っていました。しかし、やはりツーリングマップルの情報というものは GoolgeMap がある今でも大いに価値があるものだと再認識。数年の時を経て再び購入しました。



そこでふと思いました。今あの時みたいにツーリングマップルだけでドライブしたらどうなるんだろう?と。今は車ですのでナビがありますし、スマフォで目的地の情報をいくらでも検索できるのですが、あえてそれらをやめてしまおうと思ったわけです。


そんなわけで、ナビとスマフォの検索を封印し、ツーリングマップルだけで目的地に向かって走ってみました。ツーリングマップルで目的地を考え、方面の地名や国道名をある程度覚えて走り出します。ナビを入れてないとなんとなく落ち着きません。車はバイクと違って車幅がでかいので、道を間違えてもUターンがしにくいため気を使います。


高速道を抜け、とりあえず目立つので確実にたどり着ける道の駅にやってきました。「道の駅あいの土山」です。


ここはツーリングマップルに「ソフトクリーム入れ放題」と書いていたので気になっていました。


これが入れ放題の現場です。

400円払うとアイスのコーンが渡されます。そのコーンにアイスを好きなだけ盛ってくださいということでした。



うーん頑張ったつもりですがもうちょっといけたかも....すれ違った子どもは凄まじい塊が載っていたので尊敬しています。



なんと初桜も売っていました。今回は保冷バックがなく、また家の冷蔵庫にはすでにたくさん日本酒が入っているので諦めました。



実はドロドロなので...遠目でパシャリ。


ここから土山宿を目指します。といってもすぐそこですけど。ナビが使えないのでそれっぽい案内板を探します。ナビなしツーリングは道を走るのは実は結構簡単で、目的地の細かい場所に到着するのが難しかったりします。事前に調べてもないのでマトモに車が入れる幅の道なのかとか一切わかりません。



とはいえそんな騒ぐようなものでもなく。一度素通りしてしまいましたが、細めの街道を少し走ると資料館に到着しました。駐車場もありました。入館料と駐車代、どちらも無料です。



この宿場町の全長は2.5kmだったそうです。この距離だと、現代人なら30分ぐらい歩いてもまだ宿場町を抜け出せない感じですかね。土山宿は難所「鈴鹿山脈」の前にある宿場町なので、必然的に多くの旅人が宿泊することになり大変賑わったそうです。



資料館の階を上がると、なにやら展示物が。



東海道宿場町の名物が並んでいました。各地の名物を食べるのが楽しみだったと書いてあって、今と変わらんなと思ったり。


宿場町も少し歩いてみました。



帰りは時間があったので下道で。もちろんナビ無しでツーリングマップルのみ。国道1号線を大津方面へ走りつつ、国道307号線経由で信楽を抜ける三段です。



国道307号線は道幅も十分にあり快走です。



信楽はもう何回走ったかわからないのでナビどころか地図も不要です。



茶畑があったのでよって帰りました。



全部ツーリングマップルで走り切ることで、少し昔の気持ちを思い出しました。ツーリングマップルを素早くバラララーとめくって現在地を探すあの手癖は今も健在でした。冒険感があって楽しいですね。なんでもかんでも効率よく進めるだけがベストではないことを教えてくれます。もっとも完全に地図を頭に叩き込めればナビよりも効率良くなるかもしれませんが。


次はもうちょっと複雑なルートを設定してみたいですね。

MAZDA3 FASTBACK 15S touring (AT) インプレッション

昨年、MAZDA3 FASTBACK 15S touring (AT) が納車されました。

funnelbit.hatenablog.com

納車から半年以上が立ちましたので、ここらでレビューしてみようと思います。既に様々な方が YouTube などで詳細レビューをされていますが、長々としたレビューを文章で見たい人のためにつらつらと書いて見ようと思います。

デザイン

まずはデザインからです。MAZDA3 FASTBACK のデザインは既に散々話題になってますが、改めて見てみたいと思います。

外装デザイン

誰が見ても直感でカッコ良いと感じるデザインに仕上がっていると思います。塊感が見事に表されています。「誰もがひと目で惚れるデザイン」というのが、よく開発者インタビューで語られていて、そんなこと可能なのかよと思ったのですが文句無しで達成できているのはすごいことだなと思います。

前から見ると、迫り来るようなライト周りと迫力あるグリルがありながらも、余計な装飾がなくすっきりとしており、低めに見えるデザインかつメッキを使っていないためスポーティーな印象を受けます。ワイパーは未使用時に勝手に収納され車体内外からの見た目を良くしているということでこだわりを感じます。


15S と 15S touring グレードより上のグレードでは、デイライトがついたり、ポジションランプが LED になったりします。まあ個人的にはそこまで気になっていません。

横から見ると多少前後短く見えますが、FFかつ4人がゆったりと乗車可能なパッケージングと考えると、工夫され比較的伸びやかなデザインになっているかなと思います。キャラクターラインを廃して曲がりだけで表現されたサイドの造形はとにかく驚きで、光を見事に車体のデザインに取り込むことができています。ドアのウィンドウも面積を大きくしないことで、デザイン優先でシャープな印象を出せていると思います。ここで突然ウィンドウ下にメッキを使っていますが特にこれで破綻している感じもないのでまあ良いのかなと思います。

後ろから見ると3ナンバー幅なワイドな車体で、かつ上に向かって絞り込むような形になっています。これによって車体下部がどっしりとして見え、非常に走りを期待させるようなデザインを実現できています。リアのデザインも非常に特徴的で、特別感を強く感じます。


15S と 15S touring グレードの注意点として、このテールランプのうち、内側2つはダミーであるという仕様があります。光そうですが、光りません(笑)。これは契約してから気がついたのでまじか!!という感じでした。このランプを光らせるべく、MAZDAディーラから内側のテールランプを取り寄せて取り付けている人もいました。

内装デザイン

国内のこの価格帯で考えるとトップクラスであると思います。手が触れそう、目が行きそうな場所にはほとんどソフトパッドが使われているほか、スティッチもかなりの箇所で入っています。ダッシュボード上はハードプラのような見た目かと思いきや柔らかく、割と上質なものが使われています。15S Touring は一番下から2番目という安価グレードですが、それでも上位グレードと比べて安っぽさが全然感じられないのは驚きです。


ナビ画面はちょっと上が短いので、上が進行方向だと道の先がなかなか表示されないため、もう少し上に長いほうが良かったかなと思います。ただし運転を邪魔しないのでこれはこれで満足かなと思っています。


運転席は適度な包まれ感があり、運転に集中できる環境が整っています。メータ、各種スイッチ類、シフト、全てが適正な位置にあり素晴らしいです。

メータはセンターのみ液晶なのですが、アナログメータ表示にするとぱっと見で全部物理メータに見えるのは面白いです。針のアナログな動きも見事に表現できていると思います。表示切り替えも可能で、車体周りのセンサを図示した画面にできます。一方で、スポーツモードにしたら赤くなるとか、よりスポーティーなメータ表示にするとか、そういったおもしろメータみたいな表示機能はありません。

ヘッドアップディスプレイがこの価格帯で標準装備なのは驚きです。速度、ナビの車線案内、左右からの車接近警告がでます。視線を正面からほぼ動かさずに確認できるので、予想以上に便利で安全性にも寄与していると思います。欲を言えばブレーキホールドの状態も出て欲しかったです。


このグレードはシートがファブリックですが妙に質が良く見えます。革シートは暑いとかいう人はむしろこっちの方が嬉しいかもしれません。ただどうしても革シートに比べると姿勢が少し滑りやすいかなという感じはあります。どうしても革シートにしたければ、2022年4月現在では1.5リッターエンジンではラインナップがありませんので、2リッターもしくはディーゼルやSkyActive-X をチョイスする必要があります。自分は他社製の革シートカバーをつけることにしました。

このシートはもう散々あちこちで言われていますが、骨盤を支えるシートです。このシートもマツダの思想が色濃く反映されているもので、骨盤を立てるという機能を売りにしています。初めは違和感を感じて、また中々ベストなポジションが決まらずに落ち着かなかったのですが、慣れるとサポート力の強さを感じとても良いです。

ドライビングフィール

MAZDA3 は複数のエンジンラインナップがあり、それぞれで重量やエンジンのフィールが違うため車の性格が異なるようです。このレビューはあくまでも1.5リッターガソリンエンジン専用として御覧ください。

エンジン


この車のエンジンは 1.5L の NA レギュラーガソリンエンジンです。型番は P5-VPS で6,000回転まで回して111馬力。最大トルクは 3,500 回転まで回して 146N・mとなっています。かつてアクセラと呼ばれていた時代と同じ型番のエンジンで、ロードスターはこのエンジンをベースに専用部品を搭載しまくった P5-VPS[RS] です。


111馬力しかないスペックを見てわかる通り、パワーはありません。じゃあパワー不足なのかというとそうではないと思います。では意外とパワーが有るのかというと、それもそうではないと思います(え?)。


まず、車体重量がエンジンのパワーより勝っている、という感じはどうしてもあります。もう少し細かく言うと、アクセルの踏んだ量に対しトルクが少し乏しい感じがあります。停車状態から発進するときにはこの感覚が顕著です。これには少量踏んだだけでドカンとパワーを出すような、他メーカーが(車種によっては)採用している味付け(悪く言うと、パワーを誤魔化す味付け)をしていないというのも関係していると思われますが、エンジンの性能的にもしょうがないものです。


しかしながら、驚くべきは吹け上がりと反応の良さです。アクセルを踏んだとき、エンジンがすぐに反応する感じがあり、また比較的軽やかに吹け上がります。良い意味で1.5リッターのNDロードスターを低コスト車向けにデチューンしたような感覚で、ブオーーー!という気持ちの良い音とともに吹け上がります。


この反応の良さと吹け上がりの軽やかさによって回転がキレイに上がりますので、トルク感が少なくても、ほしいパワーを引き出せるところまで回転をスイッと持っていける感じがあります。これが若干のアンダーパワー感を打ち消しにいっている印象があります。このようなエンジン特性があるために「速くはないが、これでパワーは必要十分じゃない?」という評価に落ち着くエンジンになっていると思います。

街乗り

街乗りでは、車体がエンジンに勝っている感覚はあるものの、パワーがないなあと感じるまでもない絶妙な印象に落ち着いています。


発進時は少しアンダーパワー感がありますが、回転を上げてしまえば、少し踏むだけでぐいっと車体を前に押し出してくれる力感があります。そのためキビキビ走りたければ回転を積極的に上げていく必要があるのですが、吹け上がりがスムーズで音も良いことから、エンジンを回すことに対してネガティブな印象がなく、むしろ積極的にアクセルを踏みたくなってしまうエンジンになっているのが好印象です。


これによって、ただ近所のスーパーマーケットに買物を行くだけでも楽しませてくれるエンジンとなっています。街乗りの場合は大体2000~3000回転前後をウロウロすることになると思いますが、このあたりはとても気分がよく、無駄にアクセルを踏みたくなるようなフィールになっています。


ただしどうしてもネガが目立つのが坂道に差し掛かったときで、特に立体駐車場の入り口などは、これまで平地ではスイーっと進んでいたのがいきなり登らなくなったぞ!みたいな感覚を感じます。ぐいっと踏むか、シフトダウンすれば勢い良く登りますが、そういうアクションが必要となるエンジンです。エンジンの音は良いため不快感はありませんし、NAの軽自動車のようなパワー不足感ではないということは強調したいと思いますが、このエンジン、実際は MAZDA2 クラスの車だとピッタリなんだろうなあという印象です。

ワインディング

ワインディングでも街乗りと同様、車体がエンジンに勝っている感覚がずっとついて回るものになっています。この感覚はどんなに回転数を上げパワーを出しても変わりません。所詮は111馬力なので、回転を上げに上げてもパワーは大したことはないです。カローラアクシオとかと同じレベルのパワー感です。


ただしやはり吹け上がりがよく、また高回転域までキレイに回っていく印象があります。トルク感を強く感じる部分は4000回転ぐらいで打ち止め感がありますが、やはり吹け上がりの良さで力感をカバーしている感じがあります。またワインディングでは基本的にはずっと走り続けているので、街乗りのような発進時での重さが感じにくいです。


特に良かったのはギアを下げたときのエンジンブレーキです。ブオォォン!という気持ちの良い音とともに減速するこのフィールはめちゃくちゃスポーティーです。MT モードを使って無駄にギアを落としたくなります。


速度は出ないものの、音や反応の良さ、回転の吹け上がりの良さといった、性能というものでは表すことのできない、気持ちよさという部分で楽しませるエンジンになっているのかと思います。逆に言えば、性能を求めている場合はそれに答えることはできないエンジンであると思います。性能を引き出してガンガン走ってやるぜ!!と思ってワインディングに行くとがっかりすると思われます。


かく言う自分も正直初めてワインディングを走ったときは、パワー感が乏しくて拍子抜けしてしまいましたが、最近は特にそうも思わなくなりました。パワー感に慣れてしまったというのもあると思いますし、パワーが足りなければその分踏んでエンジンを回せば良いので、ガンガン回すアクセルワークに慣れてしまったのかもしれません。

高速道路

この車で一番驚いたのは高速道路です。正直このエンジンと AT の組み合わせが一番光るのは高速道路かもしれません。


まず一般道やワインディングでエンジンが車体に負けてる感を感じていたことから、高速道路でもどうせそうなんだろうと思って乗ってみると、驚くほど速度を乗せやすい事に気が付きます。特に追越車線を走るとき、少し強めにアクセルを踏むと、AT が意図を汲み取ったようにすぐにシフトダウンし加速します。流石に爆速というわけではありませんがスムーズに速度が上がりますし、またその間の音が素晴らしく、ブオォォォー!!と非常に気持ちの良い音と吹け上がりで加速していきます。何度かこのフィールを体感していると「今、スポーツカーに乗ってるのかな?」と思うぐらい素晴らしいものです。加速するときは MT モードに使いたくなるのが車好きの性だと思っていましたが、正直この車で高速道路を走るということに関しては AT に全部任せるほうが気持ちが良いと思います。スポーツモードにすると更によく走るようになるのでさらに印象が良くなります。


おそらく、街中や峠道と違って平坦が多く、速度がのっている状態であることから重さのデメリットが表れにくく、そこにエンジンの吹け上がりと反応の良さ、AT の賢さが加わって、とても気分が良い加速フィールを生み出しているものと思われます。


もちろんアクセルを踏まなければゆったりと走ることももちろん可能ですし、エンジンに急かされることもないので巡航は快適だと思います。

車体操作の印象


この車は全長が 4,460mm、全幅が 1,795mm あります。車両重量は 1,340kg です。


ちなみに全幅はライバルとされるカローラスポーツが 1,790mm、インプレッサが 1,775mmです。


この1.5L エンジン搭載車は、2.0L エンジンに比べて 20kg 軽量です。1.8L ディーゼルと比べると 60kg 軽量であり、SKYACTIVE-X エンジンと比較すると、同じホイールサイズであれば 110kg も軽量です。なお、15S touring は標準で18インチタイヤを装着しています。

街乗り

車体は大きいのですが慣れの範疇です。ただし死角はどうしても感じる場面はあります。特に左折する時に、左方向から走ってくる自転車や歩行者はかなり見づらいです。危ないと感じることもあります。


あとバック駐車については、後方視界が壊滅的とよく言われますが「360度カメラがあれば全く問題ない」と思いました。まず、目視で斜め後ろを運転席から視認するのは死角が多すぎて不可能と思ってもらって良いです。諦めてください。バックカメラを使う前提になります。ただしバックカメラだけでは少し心もとない感じがあります。なぜなら斜め後ろだけでなく、各部のピラーが太かったりして死角が割と多いからですね。360度カメラオプションをつけるのはほぼ必須と言って良いと思います。これが付けば全方向を一画面で見渡せますし、接近センサーもちゃんと付いているのでぶつかりそうになったり歩行者が歩いていればちゃんと警告されますから、実は目視よりも圧倒的に安全駐車できる車となっているのかなと思います。


住宅地などによくある狭い曲道に関してはこの車の苦手とするところですが、360度カメラさえあれば全方位見ながら曲がれますので、多分この車よりも少し小さくてカメラがない車と同等の取り回しか、下手するとこちらのほうが運転が楽です。


車体の大きさの割には妙に軽快な走りを持っており、街中でも軽快感を感じ取ることができるものです。近所のスーパーに買物に行くだけでも楽しめる車体がとても気に入っています。ハンドリングとしてはわりとしっとりとした動きではあるのですが、そこに軽快さが混じっていてなんだか少し不思議な感じです。

ワインディング

ワインディングに持ち込んだ感想ですが、まず車体が大きいのが気になります。一世代前のエスティマ(全幅1700mm)よりでかい全幅は流石に日本の山道では辛い場面が出てきます。どんな車も大型化しているのでしょうがないのですが、山道は早々広くならないのでキツイなあと思っています。ただし、人間は意外と優秀でこれは乗っているうちに慣れてはきます。


くねくねした道では運動性能の良さが光ります。車体自体はさほど軽量というわけではないのですが、コーナーに対して鼻先をスッと曲げて、そのままスッとグイグイ曲がっていく印象で、これはかなり良いです。ただしカローラスポーツのほうがサスの上質感は高かったと思います。踏ん張りつつ、しなやかに曲がる印象でした。ただしスポーティー感はそんなには感じられず、そこは MAZDA3 に軍配が上がります。荒れた路面ではネガを感じる揺れはあるにはありますが、スポーティーな車であればそこまで気にするポイントではないのかなと思いました。


まあ正直ハンドルはもうちょっとクイックな味付けのほうがスポーティー感の演出としては良いと思いますが、あえてマツダは人馬一体を突き詰めた結果そうしていないというのがあります。


目線は低めになっていて、シートを下げればめちゃくちゃ低くなるので、スポーティー感にあふれています。シートを下げれば地面が近くなり、加速感がより強くなるので速度を出さなくても満足感があります。 デフォルトの状態でもかなりシートが低く、この車が納車されてまず行ったのがシートを上げまくることでした。

高速道路

決して安定してないことはないのですが、速度が上がるとちょっと車が動きたがる感じがあります。軽快な操作フィールが高速道路でも残っている感じです。もうちょっとだけ落ち着いても良いとは思いますが、不満ではありません。レーダークルーズコントロールがついているので、高速道路では快適な方だと思います。

ペダルレイアウト

パッと目を引くのがオルガンペダルである点です。この価格帯でオルガンペダルの車はMAZDA以外で国内では存在しませんので、非常に貴重です。自分はオルガンペダル大好きなのでとても嬉しく思っています。


このペダルレイアウトは MAZDA の思想が色濃く出ているペダルレイアウトです。人間をコクピットの中央に座らせ、更にそのまま足を伸ばしたときに自然とペダルに触れることができるようになっています。正直はじめはそれがどう作用しているのかよくわかりませんでした。しかししばらくして別の車に乗ったときに、あまりのレイアウトの不自然さに驚きました。試乗でもわかりにくいポイントかも知れませんが、一度これに慣れると適当なペダルレイアウトの車に違和感を覚えるようになります。

ブレーキ


前後ディスクブレーキです。ちなみにサイドブレーキは電子式となっています。

街乗り

これはよくある話ですが、はじめは「なんじゃこりゃ」と思いましたね。MAZDA3 のブレーキはマツダの思想が色濃く反映されているので、ちょっと踏んでも大して効かず、踏み込んでいくとジワジワと効いていくブレーキになっています。


マツダとしては「これがコントローラブルなブレーキで理想的である」ということでこういうフィールになっています。


正直これ体験したときは「こんなに他メーカと感覚ズレたブレーキ提供されても...押し付けがましい」と思っていたのですが、慣れるとこれは素晴らしいブレーキだなと思うようになりました。とにかくコントローラブルで、狙った制動力を正確に引き出せるブレーキです。また踏み込めばしっかりと効くので必要十分の制動力があります。これに慣れると、他メーカのブレーキを踏んだときにいきなり効いて怖くて、使いづらいと思ってしまいます。


イメージとしては自転車のブレーキ感覚に近いです。ぐぐぐって感じ。

ワインディング

ワインディングでもコントローラブルでとても良いです。なんの不満もないですね。

トランスミッション(AT)


SKYACTIV-DRIVE と呼ばれる MAZDA 独自開発の6速 AT が搭載されています。個人的には AT セレクタの MT モードが前にするとシフトダウン、後ろに引くとシフトアップというのが気に入っています。BMW などヨーロッパメーカーと同じですので。

街乗り

CVT と比べると気分の良さが段違いです。また AT にも関わらず変速にダイレクト感があります。これが街乗り性能でどうかわるかどうかという話はさておき、普段乗りでも気分が良いというのは車好きにとってはとても大きなポイントです。変速ショックは全く感じられず、また変速の速度が恐ろしく速いためこれも良い点です。

ワインディング

山道だと積極的にマニュアルモードを使いたくなるのですが、これが素晴らしいです。これまで経験してきた AT のマニュアルモードはどうしてもギアを入れた後にラグがありました。


例えば MT の場合、2速から3速にする時はギアを3速に入れたら3速になり、あとはクラッチを繋げれば良いわけです。この一連の流れは人間が操作しているので、人間が操作完了と思った時点で変速は完了しています。


しかしATのマニュアルモードは電子制御ですので、3速に入れる操作を人間が完了しても即座に3速にはならず、その後機械がギアチェンジするまでアクセルを踏んだまましばらく待つ必要があります。つまり人間が操作完了と思っても変速は完了していないわけです。この人間と機械の感覚のズレというか、ラグが非常に違和感のあるのもので、運転の楽しさに影響するものでした。


前に乗っていたミニクーパー(F56型。DCT ではなく通常のトルコン AT)がまさにそうで、まあ AT だししょうがないかな、DCT だと違うのかな〜と思っていたのでした。


ところが MAZDA3 の AT についている MT モードは、このラグがとても短く、全く違和感がないものになっています。操作したらほぼ即座にギアが入る感覚で、MT よりも圧倒的に速く変速できると感じ、車を操っている感覚が変速で途切れません。これはとても素晴らしいものだなと思いましたし、一度この素早さを経験するとラグがある AT には乗れないな、とも思いました。とはいえ最近の CVT は質が上っているらしいのでそこは気になるところです。

スポーツモード

MAZDA3 のスポーツモードは、パワーをUPさせるというよりもアクセルに対するリニアさを強化するモードになっていると思います。


通常モードでは、どうしても燃費優先になっているのかアクセルを踏んでも少しタメのようなものを感じたり、控えめにエンジンを回すようになっています。しかしスポーツモードにすれば、それらがなくなって即座にアクセル操作に反応するようなフィールになります。


スポーツモードというとワインディングでの利用を考えたくなると思いますが、どちらかというと高回転を使うステージよりも、チマチマとした操作を行う日常の道や、あまり回転をあげずに巡航する高速道路でのほうが効果を実感しやすいです。


パワー感も一応上がりますが、所詮ターボも付いていない NA なので、スポーツモードにしたところでブーストアップもないためにそこまで大きく感じれるものではありません。人馬一体感をより高めるモードである、という認識のほうが正しい気がします。

使い勝手

4人乗れるスペシャリティーカーというテーマから作られているため、4人乗車はもちろんのこと、普段の生活に使えるラゲッジも確保されていると感じます。

後席


後席は3人乗れますが、スペースの関係上実質2人を乗せる空間となっています。たまに後席を「狭い」と評価されるこの車ですが、個人的には十分な空間が確保されていると思います。乗り込んでみると意外と広く、大人2人であれば十分に乗ることができます。よくライバルとして比較されるカローラスポーツよりも広いはずです。



写真のように、助手席を快適な位置に調整した状態で後席に座って見ても、十分なスペースが確保されていると感じます。


またシートの質が異様によく、リクライニングはできませんがコシがしっかりとしていて疲れにくいです。数十キロが限界という後席ではなく、高速道路を使って長距離のドライブにも利用できるようなものです。後席シートの真ん中には引き出すとちゃんとした高さで止まるアームレストもあります。窓も小さいですが全部開きますし、乗り込んでしまえば快適です。


チャイルドシートも特に無理なく設置することができます。
funnelbit.hatenablog.com


ただしスタイリッシュなデザインの関係上、乗り込み口はどうしても狭いです。この車に初めて乗る人は大抵頭をぶつけています。スポーツカーみたく腰から入るように座れば問題なく乗り込めます。


あとは同乗者に嬉しいポイントとしては静粛性の高さです。今は他の車もかなり高いレベルにあるかもしれませんが、発売当初のレベルでは素晴らしいと思います。アイドリングストップを音にしてエンジンが停止すると本当にスッと静寂が訪れるような静粛性になっています。

トランク

十分な広さがあると思います。ライバルの車と比べて少しだけ狭いとよく言われますが、今の所大人二人、乳児一人の家族3人での生活で足りないと思ったことはありません。



ベビーカーもしっかりと乗せることができます。


唯一困った場面は背の高い植木を運ぶときでしたが、正直めったに無いと思うので許容範囲内です。

まとめ


普段の道を彩りあるものに変える4人乗りカーとして素晴らしい出来だと思います。デザインは文句なく素晴らしく、内装も高レベルで車好きにとっては満足の行くものとなっていると思います。後席にも大人が乗れる余裕があり、チャイルドシートも設置可能とくれば、車好きで家族もいる家庭でも検討できる車に仕上がっていると思います。


一方で1.5リッターエンジンについては、町乗りでスポーティーさを感じることからワインディングへの期待を膨らませすぎると、ワインディングで「あれ??こんなもの??」という印象を受けると思います。見た目がスポーティーなので過激な走りを期待してしまう人も多いのかと思いますが、エンジンそのものはスポーティーテイストこそあるものの、刺激やスポーティーな加速性能といったものはほぼありません。そのため街乗り試乗で吹け上がりが比較的良いということでスポーティーカーテイストを過剰に期待するとがっかりする、ということになります。


ただし、普通の乗用車1.5LNAレギュラーガソリンエンジンの中では圧倒的に吹け上がりが良いことから、スポーティーのエッセンスは確実にありますし、車体の運動性能もとても良いので、十分スポーティーカーとして認識できるものです。またこの価格帯で、エンジンの吹け上がりがよく、4人が問題なく乗ることができる車となっている点がポイントかなと思っており、そんな車は国内をみても他にないので、非常に素晴らしい存在ではないかと思います。


また普段の街乗りでも気持ちの良いエンジンの吹け上がりが楽しめるというは当初思っていた以上に良い部分で、例えばチャイルドシートに子どもを乗せていて、慎重に運転しないと行けない場面が毎日続いたとしても、エンジンの吹け上がりが気持ち良いので満足できるという車になっています。


まあ正直いうと、見た目が走りのやる気に満ちているので、それに合わせてもう少しエンジンの性能は欲しかったと思っています。ターボほしいな~とか。ただし値段との兼ね合いもあるで、とりあえず現状は満足の行く買い物をしたかなと思っている次第です。

MAZDA3 FASTBACK は子育て車として使えるか?

MAZDA3 FASTBACK を購入検討しつつも、子育てに使えるか迷っている人は割といるのではないでしょうか?特にチャイルドシート、ベビーカーを載せたらどうなるのかというところが気になると思います。自分もそうでした。

結論から言うと、赤ちゃん一人であれば自分が所有しているチャイルドシート、ベビーカーともに問題なく載ります。ただし子どもの乗せおろしはしんどさがあります。

チャイルドシート

チャイルドシートは運転席後ろに設置しました。こんな感じです。

運転者の身長 168cm に合わせて調整しています。チャイルドシートはまだ生まれて2ヶ月程度なので後ろ向きに設置し、チャイルドシートをフルリクライニングしています。快適に運転できるシートポジションで、後ろ向きで取り付けするとクリアランスがあるのか気になっていましたが問題ありません。ちなみにチャイルドシートはエールベベのクルット6iです。

ailebebe.jp

シートベルトが跳ね上がって子どもを乗せやすいという「ジャンピングハーネス」が魅力の商品です。MAZDA3 はお世辞にも子どもを乗せおろししやすい後席にはなっていません。スクワットのような姿勢で行う必要があります。そのため乗せやすいチャイルドシートを選ぶことは重要だと考えます。

また今回はこの商品で問題なく載りましたが、もしも身長が高い人で運転席後ろにチャイルドシートを設置する場合は、コンパクトを売りにしたチャイルドシートを選ぶとより快適に運転できるのではと思います。Combi の商品は比較的コンパクトなものが多いようです。

www.combi.co.jp

ベビーカー

ベビーカーをトランクに載せた状態はこんな感じです。トノカバーにも干渉せずに収まっています。

ベビーカーは Cybex のメリオカーボンです。 https://cybex-online.com/ja-jp/strollers/melio-carbon3-jp/294

余ったスペースにおむつのパックを置いたり、お出かけセットを置くこともできると思います。

注意としては、MAZDA3 FASTBACK のトランク容量は 334L で十分な大きさがあるものの、トノカバーがあることと、トランクは下にえぐるように作られていることから、意外と入り口が狭く大きなものを入れようとするとつっかえたりします。また乗せ口が割と上にある印象なので、ぐいっとベビーカーを持ち上げなければなりません。

メリオカーボンは非常にコンパクトかつ軽量な A型ベビーカーですが、それでもある程度はトノカバーとトランク下部に当たらないように気をつけて積み込みをする感じになります。そのため、ベビーカーはコンパクトに畳めるものであればあるほどよい、ということになります。とはいえ安定感のあるベビーカーは大きい傾向があるので安定感を求めるとコンパクトなものをチョイスするのは難しい、というのはあります。まあトノカバーさえ外し、あとは重さを頑張れば大きめのものでも入ると思います。

車内でのオムツ替え

そんな空間はないので不可能です。まあ可能な広さのある車だったとしても、オムツ替え時、車内におしっこ爆散の危険があるのでオムツ替え室を探して行うのが良いのではと思います。

車内でのミルク

試したことないのでわかりませんが、まあできるとは思います。今のところはオムツ替えとミルクはセットで行っているので、どのみち授乳室やオムツ替え室を探してそこで行っています。

チャイルドシート横の空間

助手席をそれなりに快適な位置にしていたとしても、後部座席に十分な空間があり大人が余裕で赤ちゃんの横に乗ることができます。もし狭ければ助手席をより前にスライドすれば良いだけですし、今の所その必要性は感じていません。

乗せおろし

上にも書きましたが流石に楽ではありません。腰を曲げたり、スクワットみたいな体制をとったりする必要があります。しかしそこまでたくさん乗せおろしするわけではないので、MAZDA3 FASTBACK のデザインや走行の楽しさとのトレードオフとしてまあ許容範囲かなと思っています。これを楽にしたければ THE ファミリーカーというものに乗るしかなくなります。

後部座席のエアコン

MAZDA3 はいかなるグレードであっても後部座席にエアコン吹出し口はありません。海外向け仕様にはなぜかあるらしいですが...。ただし今の所それで問題にはなっていません。夏は後席地獄ではと思ったのですが、前のエアコンを数分つけると寒いらしく、むしろ運転席の方が暑いです。後部座席は窓が狭いので、光が入りにくく、運転席で感じているほど太陽光の熱は来ないようです。冬も数分暖房をつけるだけで十分暖まります。

さいごに

MAZDA3 FASTBACK は、少なくとも大人二人、赤ちゃん一人であれば子育て車として使えると思います。もちろん子育てを意識した車ではないのでそこは留意して所有する必要はありますが、かなり不便というわけではないので問題ないかなと思います。とにかくチャイルドシートとベビーカーが問題なく載るという点、これだけでかなり選びやすくなるのではないでしょうか。これから子育てをする予定があるが、ファミリーカーは避けて運転の楽しい車にしたい!という方の参考になれば幸いです。

(実は自分がまさにそのパターンでした。というよりなぜ車を買ったかというと、妻の妊娠がわかって、子育てのために絶対車があったほうが良いと思い MAZDA3 FASTBACK を購入したという経緯でした。賢い選択をするならミニバンになるのは百も承知ですが、走りを諦めたくなかったので。)

ちなみにディーラーの営業の方によると、子育て世代に人気な車はマツダだと CX-5 か CX-30 とのことです。

GraphQL スキーマを図にして、状況をわかりやすくしよう

GraphQL で開発していくと、GraphQL スキーマが膨らんでいきます。また GraphQL スキーマは分割できますが、これを進めるとどのフィールドがどこと関係しているのか、追うのが難しくなってきます。


そこで GraphQL スキーマを図にして追ってみようと思うわけです。図に吐き出してくれるツールとしては Graphqlviz があり、npm でインストールしてターミナルでスキーマを指定してコマンド叩けば簡単に図にできます。
github.com

ただし複雑なスキーマをこれで単純に描画すると凄まじい事になり、例えば GitHub GraphQL API の パブリックスキーマ に対し生成を試みると、
f:id:funnelbit:20220107175344p:plain
これは一部抜粋ですが、これだけでもまさに混雑的リレーションの小宇宙という感じで追うのが不可能です。ちなみに単純に GitHub GraphQL API の パブリックスキーマ npx graphqlviz schema.docs.graphql | dot -Tpng -o graph.png とかすると 100MB の png 画像が爆誕します。

普段開発しているプロダクトのスキーマはここまででは無いにせよ、単純な図で追うのはもはや厳しかったです。そこで現在は GraphQL Voyager というものを使っています。
github.com

こちらは Web アプリケーションのライブラリであり、提供されているコンポーネントを呼び出すとイントロスペクションを fetch してブラウザ上に図を描画してくれます。デザインが工夫されていて見やすいですし、さらに図を押すとハイライトされたり、検索できたり、表示するフィールドを絞り込めたり非常に便利でした。
f:id:funnelbit:20220107181131p:plain

ここにサンプルがデプロイされているので触って遊ぶことができます。
apis.guru


手っ取り早く手元で試すなら、example ディレクトリに行って、fetch している url を書き換えて動かすと良いと思います。
github.com