Infinito Nirone 7

白羽の矢を刺すスタイル

嬬恋キャベツヒルクライムに参加してきた

今年からサイクリングイベントに参加し始めてはや3回目の大会となりました、群馬県嬬恋村の万座ハイウェイを自転車専用に貸し切って開催された嬬恋キャベツヒルクライムに参加してきました。

cabe-hill.net

距離は約20kmで1000mの標高差を登ります。平均勾配で見ると5%くらいと易しめに見えますが、実際には途中で平坦や若干の下りもあるため、たまに10%ほどの坂が現れたり、地味に長い緩斜面が続いたりと、走りきってみると結構キツめだったような印象があります。以前は参加者全員がフルコースを走るイベントだったようですが、今年はファンライドコースが設定されており、途中のホテルまでの序盤のじわじわくる坂を楽しめるコースもありました。

かなり地元を上げて町おこしも兼ねて力を入れているようで、プロサイクリングチームをゲストに迎えて一緒にヒルクライムレースをしたり、キャベツ(嬬恋村はキャベツ生産で有名)を使った料理をふるまっていただけたり、キャベツ1玉をお土産にもらえたりと、村ならではの特色があるイベントでした。自分もキャベツ1玉を持って帰ってきたので、お好み焼きにして食べたいと思います。また、周辺のホテルとの連携も強く、ホテル利用者専用の駐車場があったり、ホテルで参加受付ができたり、参加者向けの特典があったりもしました。自分が泊まったホテルはヒルクライムコースをさらに登ったところにあって、当日いちどコースを車で降りてくる必要がありますが、スタート時間が午前9時と余裕があるので、朝食を食べてひとっ風呂浴びてから降りても間に合うような感じです。

当日は天気もよく、標高が高いながらも程よく涼しい気温でした。全体で1000人ほどの参加者がいたようですが、滞りなくスタートができました。

序盤の万座ハイウェイにはいるまでの道も地味に斜度があって、ウォーミングアップにはちょうどよい気がします。ハイウェイに入ってからも斜度は地味にきつめなので、あまり飛ばしすぎない程度にスルスルと登っていきました。 ファンライドコースのゴール地点を過ぎたところや、給水地点の直前の坂がきつかったりもしましたが、終盤にかけてはいいペースで登れた気がします。時間はあまり意識していませんでしたが、一時間半くらいを目標に登れそうな感じだったので、そこを目指して登りました。

終盤も地味な斜度の強弱がありました。途中マルコファヴァロさんやNIPPOの選手と間近なところで走ることもできて楽しかったです。結局タイムは1時間20分と目標よりも10分はやく登りきりました。さすがにこの時期でも標高1800m付近は寒く、指まで覆うグローブを忘れてきたのは失敗したなと思いましたが、何とか無事に下山も済ませました。

下山後に特別にマッサージを受けて、腰回りを揉んでもらいました。すごい気持ちよかったのですが、どうやらお尻の筋肉が凝り固まっているようで、マッサージを受けているときもウッとなったのですが、アドバイスとしてそこをストレッチすると腰や下半身も楽になると教わったので、お尻のストレッチを試してみようと思います。

NuAns NEO Reloaded 使用感

Nexus5X から次の端末を探しているときに NuAns NEO Reloaded がリリースされたのを機に乗り換えて、2ヶ月ほどが経ったので使用感を書き残しておこうと思います。

概ね Vanilla Android なので、Nexus シリーズのリファレンス機に慣れていれば特に違和感なく使えると思います。若干指紋認証のハードウェアが鈍い気がしますが、表についているので便利ではあります。 性能としてはハイエンドではなくミドルレンジの端末なので、グラフィックがすごいゲーム(小並感)を楽しむには厳しい気もします。ただ自分はそこにこだわりはなく、普通のアプリを使う分には問題ないと思っています。少なくとも Nexus5X に比べれば圧倒的にサクサク動いてくれますし、使用していく中で発熱をしてもパフォーマンスに影響があるようには見えないので、Google Maps をカーナビ代わりに使うなどしても問題ないとおもいます(少なくとも3時間のドライブで Google Maps を立ち上げっぱなしにしてもサクサク動いてくれたので満足)。

問題があるのは、ディスプレイのタッチ検出の様子がおかしい場合があることです。熱を持つとよく起こる気がしますが、タップをしているのに拾わない、タップしていない場所でタップを誤検出する、の2つが稀によく起こります。 タップしているのに拾わないのは、開発者オプションでタップを表示すると、タップの表示は確かにされているのにタッチイベントがアプリに伝わっていないように見えます。ただ、ゲームでタップした場所に何らかの視覚効果が出るものでためすと、その視覚効果が出ているのも確認したので、一体何が問題でタップをハンドリングできてないのかよくわかりません…

開発者としては、開発者オプションにある「バグレポートのショートカットを追加する」機能が死んでいるのが気になります。有効にしても電源メニューにバグレポートのショートカットは出ないので、ここぞというときにもたもたしてしまうので残念です。

総じて、ちょっとしたゲームで遊んだり動画を見たり、普通のアプリを使っている分にはサクサク動いてくれてよいな、でも開発機としては困ることもあるな、という印象です。 現場からは以上です。

SMS が相手に届いたかどうか判定する

SMS や MMS と言ったメッセージのやりとりの仕組みには、Delivery Report という機能があります。SMS をおくると、キャリアが Delivery Report を送り主に返します。この Delivery Report を見ることで、SMS が相手に届いたかどうかが分かります*1

SMS や MMS をおくるには、SMSManager を使います。例えば、単純なテキストメッセージをおくるのであれば、sendTextMessage メソッドを呼び出してメッセージを送ります。 他にもいくつか用途に応じて異なるメソッドが用意されていますが、ほぼどのメソッドでも sentIntent と deliveryIntent というPendingIntent型の引数があります。

これらは、メッセージ送信中にエラーがあったかどうか、またメッセージが相手に届いたかどうかをブロードキャスト Intent としてコールバックするために使われます。 sentIntent はメッセージ送信が成功したかどうか、エラーならばどのようなエラーがあったかをブロードキャストします。電波がなかったり、PDU が空だったり、あるいはサービスに未登録だったり、様々な理由で SMS を送れない場合はこのブロードキャストが飛んできます。 一方で deliveryIntent は相手に届いたかどうかを、Delivery Report を元にブロードキャストします。

ここまでの話は公式のリファレンスにも記述してある内容ですが、実は deliveryIntent は必ずブロードキャストされるわけではありません。

これは、キャリアが Delivery Report をサポートしているかどうかによって変わります。例えば、T-Mobile や Verizon は Delivery Report をサポートしているようですが、AT&T はサポートしてないようです*2。また、場合によってはフェイクの Delivery Report を生成することもあるようで、届いていないのに届いているように見せかけるものもあるようです*3

単純に SMS を送信できたかどうかだけであれば、sentIntent のブロードキャストのみを使って判定できるので、届いたかどうかが必要なければ deliveryIntent の PendingIntent は null にしましょう。

RxJava 1.x -> 2.x: Observable.OnSubscribe<T> から ObservableOnSubscribe<T> へ移行する

RxJava 1.x には Observable の static なインナークラスとして Observable.OnSubscribe がいました。Javadoc にあるとおり、Observable を subscribe したときに呼ばれるメソッドを定義するためのフックになるクラスです。

RxJava 2.x ではインナークラスではなく ObservableOnSubscribe というクラスになっています。また、オーバライドすべきメソッドはcall(Subscriber<? super T>)ではなくsubscribe(ObservableEmitter<T>)になっています。

Observable.OnSubscribe<T>#call(Subscriber<? super T>)のなかで、unsubscribe したときにリソースの開放やリスナーの解除などをするフックを作っていた場合、RxAndroid のMainThreadSubscriptionでフックすることになります。そしてそのインスタンスSubscriber<? super T>#add(Subscription)に渡します。 これを RxJava 2.x に移行するとき、MainThreadSubscriptionMainThreadDisposableに、Subscriber<? super T>#add(Subscription)ObservableEmitter<T>#setDisposable(Disposable)に書き換えます。

ビーナスライン

最近は毎日30度超えの真夏日で、自宅から日帰りで行って帰ってこれる場所では暑すぎて熱中症待ったなしだと思ったので、電車輪行の練習も兼ねて長野県茅野市から松本市に至るビーナスラインを走ってきました。 電車での移動距離もそこそこあるので、特急に乗ってシュッと行ってシュッと帰ってきました。調べてみるとスーパーあずさは電車輪行しやすそうだったので、行き帰りともにスーパーあずさのチケットを取りました。

朝いちのスーパーあずさで立川から茅野まで行き、そこからまっすぐビーナスラインを走りました。

まずは茅野から早速ずいずい坂道を登って蓼科湖に。

f:id:KeithYokoma:20170716102041j:plain

蓼科湖で少し休憩と軽食を取って本格的な山登り。

f:id:KeithYokoma:20170716111704j:plain

途中の見晴らしのいい駐車場でハリボーをムシャムシャ。

f:id:KeithYokoma:20170716112240j:plain

白樺湖を超え、車山高原へ向かうところの駐車場で白樺湖をのぞみ休憩。

f:id:KeithYokoma:20170716115907j:plain

逆側も。

f:id:KeithYokoma:20170716120145j:plain

車山高原では鹿肉のジビエバーガーとソフトクリーム、コーヒーでお昼。

f:id:KeithYokoma:20170716122020j:plain

スッと登って途中の駐車場。

f:id:KeithYokoma:20170716130802j:plain

更に奥地へ。

f:id:KeithYokoma:20170716140949j:plain

360度大自然がのぞめるパノラマ!!

f:id:KeithYokoma:20170716141602j:plain

f:id:KeithYokoma:20170716141615j:plain

本当はさらに美ヶ原の北をぐるりとまわりたかったのですが、天候と体力と時間の関係で手前で松本に降りることに。 降りてきてからは松本城を見たり旧開智学校を見たり、大道芸を見たりしました。

f:id:KeithYokoma:20170716153310j:plain

f:id:KeithYokoma:20170716154034j:plain

無事に松本駅に到着。一瞬だけ市内で雨に振られましたが、それ以外は概ね涼しく心地よい天気でした。

f:id:KeithYokoma:20170716163402j:plain

初めての電車輪行でしたが、良い感じに一日を過ごすことが出来ました。そして一度走ってみたかったビーナスラインを自転車で走ることができてとても楽しかったです!また行きたい!!(次はもう少し身軽にして…)

<merge> タグをつかったレイアウトのプレビューを期待通りに表示する

Issue

Fragment を使わず View をベースにしてレイアウトを組むと、Fragment と同じような役割をもった CustomView を作ってレイアウトを組みます。 このとき CustomView は何かしらの ViewGroup を継承することになりますが、そのレイアウトファイルのルートを<merge>にしないと無駄な ViewGroup がひとつ挟まってしまいます。一方で、<merge>をそのまま使うと、レイアウトのプレビューでは親が何になるのかわからないため、期待通りの表示ができません。

Solution

tools 属性に<merge>の親が何になるかを指定するtools:parentTagが AndroidStudio 2.2 から増えています。

<merge
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:parentTag="android.widget.LinearLayout">
    <!-- views -->
</merge>

tools:parentTagには親となる ViewGroup の名前を指定しますが、Android フレームワークの ViewGroup であっても FQCN をつかいます。またandroid:layout_widthandroid:layout_heightを設定しないとプレビューがうまく表示できないことに注意しましょう。

See Also

stackoverflow.com

Kotlin でかいた interface を Retrofit に食わせたときのエラーに対処する

TL; DR

Kotlin & @Body · Issue #1805 · square/retrofit · GitHub

問題

Retrofit で REST API のクライアント実装を生成する時、Kotlin で書いた interface を渡すとき、メソッドにジェネリクスを使った引数がいるとまれに次のようなエラーメッセージを吐き出してクラッシュします。

java.lang.IllegalArgumentException: Parameter type must not include a type variable or wildcard: java.util.List<? extends Something> (parameter #4)

たとえ Kotlin のコード上ではワイルドカードを使っていない場合でも、Java に変換する過程でワイルドカードに翻訳*1されることがあり、このような問題が発生します。

対処

@JvmSuppressWildcardsというアノテーションを使います。メソッドに対してこのアノテーションを付けることで、Java への変換時にワイルドカードを使わないようになります。