Celeste Engineer

Androidとか自転車とか

RecyclerView の item に focus が当たったことを検知する

やりたいこと

旧来の AdapterView (ListView や GridView など)でいうところの OnItemSelectedListener と同じように、RecyclerView がもつアイテムにフォーカスが当たったときにその情報をコールバックする方法です。

方法

RecyclerView には OnChildAttachStateChangeListener というインタフェースが定義されています。このインタフェースのメソッドで、Adapter の生成する View が RecyclerView に attach されたタイミングが分かるので、そこで attach された View に OnFocusChangeListener をセットしてフォーカスが当たったことを検知します。

class FocusListeningRecyclerView(context: Context?, attrs: AttributeSet?, defStyle: Int)
     : RecyclerView(context, attrs, defStyle), RecyclerView.OnChildAttachStateChangeListener {
  var focusListener: OnItemFocusedListener? = null

  constructor(context: Context?): this(context, null)
  constructor(context: Context?, attrs: AttributeSet?): this(context, attrs, 0)

  override fun onAttachedToWindow() {
    super.onAttachedToWindow()
    addOnChildAttachStateChangeListener(this)
  }

  override fun onDetachedFromWindow() {
    removeOnChildAttachStateChangeListener(this)
    super.onDetachedFromWindow()
  }

  override fun onChildViewAttachedToWindow(view: View?) {
    view?.setOnFocusChangeListener { child, hasFocus ->
      if (!hasFocus)
        return@setOnFocusChangeListener
      focusListener?.onItemFocused(getChildAdapterPosition(child))
    }
  }

  override fun onChildViewDetachedFromWindow(view: View?) {}

  interface OnItemFocusedListener {
    fun onItemFocused(position: Int)
  }
}

ツールド東北

ツールド東北に同僚と参加してきました。

出場するのは日曜日の南三陸コース。前日に民泊のお家に到着して、そこから受付をしに自転車を組み立てました。
f:id:KeithYokoma:20170920100235j:image

石巻の会場にはSubaru XV が!上には Bianchi の自転車が乗っかっていて、よさそう(小並感)と思いました。普段はFitやSwift、Demioくらいのコンパクトカーで十分だと思っていましたが、コンパクトSUVも使い勝手が良さそう。コンパクトカーだと荷室の広さではFitの圧勝なのでな…
f:id:KeithYokoma:20170920100257j:image
同僚は去年も参加していて、今年も多分ピカチュウがいるとおもう、ということで探したらありました。
f:id:KeithYokoma:20170920100320j:image

受付をサッと済ませて民泊のお家に帰りました。オーナーのおばちゃんが料理大好きで、晩御飯が超豪華!
f:id:KeithYokoma:20170920100336j:image

滅多なことでは食べないカニ、最近値上がり気味のサンマ、そして初めて食べたホヤ。お野菜や漬物などとにかくおかずがたくさん出てきて、ご飯なしでも満腹になりました😊
f:id:KeithYokoma:20170920100414j:image

 翌朝は晴れていて、台風の接近を感じさせるものの自転車には乗れる天気!
f:id:KeithYokoma:20170920100433j:image

すこし風が強い場所がありましたが、女川エイドステーションに到着。すごい人!
f:id:KeithYokoma:20170920100559j:image

女川汁いただきました。
f:id:KeithYokoma:20170920100615j:image

途中人だかりができていた、眺めの良い場所でパシャリ📷
f:id:KeithYokoma:20170920100729j:image

そんなこんなで雄勝エイドステーション。ホタテ!
f:id:KeithYokoma:20170920100808j:image

太鼓の演奏も見てゴールへ向かいました。
f:id:KeithYokoma:20170920100837j:image

無事ゴール。
f:id:KeithYokoma:20170920100908j:image

 帰ってお昼を食べてからは、市内を車で回ることに。

f:id:KeithYokoma:20170920101114j:image

日和山のうえから、津波の押し寄せてきた海を見ました(写真天地がひっくり返ってる…)。車の中でも、いろいろと震災当時のことを教えてもらいました。
f:id:KeithYokoma:20170920101138j:image

仮面ライダーとツーショット。
f:id:KeithYokoma:20170920101156j:image

原画展もやっていました。
f:id:KeithYokoma:20170920101217j:image

翌日のお昼前に東京へ向けて出発。途中柿の種の車が走っていました。

f:id:KeithYokoma:20170920101259j:image

那須高原SAで。
f:id:KeithYokoma:20170920101322j:image

牛肉〜。
f:id:KeithYokoma:20170920101336j:image

二泊三日のツールド東北でしたが、民泊でのご飯がずっと美味しくて、オーナーのおばちゃんとの会話は絶え間なく続いて実家に帰ってきたような安心感がありました。

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

今年からサイクリングイベントに参加し始めてはや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

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