Infinito Nirone 7

白羽の矢を刺すスタイル

例外をネストしたクラスとして定義するときは必ず static なネストしたクラスにする

いい具合にトラブってしまったのでメモです。

クラスの定義にはいくつかの種類がありますが、あるクラスの内部にネストした(入れ子になった)クラスを定義することができます。このとき、修飾子として static をつけたネストしたクラスと、それがないネストしたクラスのどちらも正しい記述です。

public class OuterClass {

  // static でないネストしたクラス
  public class InnerClass {

  }

  // static なネストしたクラス
  public static class StaticInnerClass {

  }
}

static の有無で何が違うかといえば、static でない方は暗黙的に外側のクラス(上記の例ではOuterClass)への参照を持つため、外側のクラスのメンバにアクセスできるという点があります。 ここで、例外を何かのクラスにネストしたクラスとして定義してみたとすると、直列化(シリアライズ)で問題が起こります。

public class OuterClass {

  // static でないネストしたクラスとして例外を定義
  public class BadException extends RuntimeException {}
}

暗黙のうちにもつ外側のクラスへの参照は transient ではないので、シリアライズの対象になります。例外はSerializableを実装しているので直列化ができますが、このBadExceptionを直列化すると外側のクラスへの参照もシリアライズの対象となるものの、肝心のOuterClassSerializableを実装していないので、直列化できずに例外が投げられます。

暗黙の内に持つ外側のクラスへの参照が引き起こす問題は、メモリリークの文脈で語られることが多いように思いますが、このように直列化でも問題となります。

public class OuterClass {

  // static なネストしたクラスとして例外を定義
  public static class MyException extends RuntimeException {}
}

例外にかぎらず、ネストしたクラスがSerializableなクラスを継承する場合も同様に、static なネストしたクラスとして定義しましょう。

RxJava1 から RxJava2 へ移行する時に nullable な値とうまくつきあう

次のような RxJava1 のコードを RxJava2 に移行することを考えます。

import rx.Observable; // RxJava1

private Value nullableValue;

public Observable<Value> observeValue() {
  return Observable.fromEmitter(emitter -> emitter.onNext(nullableValue))
      .filter(nullableValue -> nullableValue != null);
}

Observable のソースとなる値は Nullable で、それを filter で null チェックをかませることで値を受け取る側は NonNull を前提にできるような感じですね。 RxJava2 では onNext() に値を渡す時点で NonNull であることを求められるため、これをそのまま RxJava2 に書き換えると実行時に例外がスローされます。

import io.reactivex.Observable; // RxJava2

private Value nullableValue;

public Observable<Value> observeValue() {
  return Observable.create(emitter -> emitter.onNext(nullableValue)) // nullable な値を onNext には渡せない
      .filter(nullableValue -> nullableValue != null); // 無意味な filter になる
}

ここで、nullableValue を onNext() に渡す時点で Optional*1 を使ってラップしてみると、うまく onNext には NonNull な値を渡せるようになります。 また、その後に filter と map を駆使すると、メソッドの返り値の宣言を変更することなく RxJava2 に移行できます。

import io.reactivex.Observable; // RxJava2

private Value nullableValue;

public Observable<Value> observeValue() {
  return Observable.create(emitter -> emitter.onNext(Optional.of(nullableValue))) // Optional<Value> は NonNull
      .filter(Optional::isPresent) // RxJava1 での null チェックと同じ効果が得られる
      .map(Optional::get); // filter で値が存在することをチェックしているので安全に get できる
}

Android の場合 Optional は GitHub - memoizr/retro-optional: A backport of Java8 optionals for Java7 を使うと古い OS バージョンでも利用できます。

*1:java.util.Optional では ofNullable でラップします。バックポート版ではofでラップします。

自転車でめぐる SHIROBAKO の聖地

この記事は SHIROBAKO Advent Calendar 2017 の 17 日目の記事です。

adventar.org

SHIROBAKO には木佐さんという自転車が趣味のアニメーターさんがいます。えくそだすっ!のときには、落合がカナンの人と話をしているところを目撃したり、8 カット上げたことあるしヨユーヨユーとか言って直後に調子でないと言ったりとしれっと重要な場面に登場していました。 そんな木佐さんが発した「仕事大事!だけどヒルクライム入賞も夢なんだ!」と言う言葉には宮森と同じく自分もはっとさせられ、気がついたら今年は自分もヒルクライムレースに何度か出場していました。分かるんですよ、あの「敵はいるけど、本当の敵はむしろ自分ッ」とか「自分を追い込んで追い込んで……こうねっ」って言いたくなる気持ち。

SHIROBAKO 放送当時はあまり気が付きませんでしたが、よく見ていると自分の家の近所だったり、よく自転車で走っている場所が描かれていることに気が付きました。 そこで今回のアドベントカレンダーのネタとして「自転車でめぐる SHIROBAKO の聖地」と題し、軽い運動がてら気軽に見て回れる場所を吉祥寺駅周辺から武蔵境駅周辺にかけて実際に走ってみたレポートをしてみようとおもいます。

コースは吉祥寺サンロード入口をスタート地点に、武蔵境駅周辺を巡ったあと松亭でフィニッシュです。

行程

今回の行程です。途中徒歩の区間があるのでその部分は自転車を押し歩きしています。

スタート:吉祥寺サンロード入口

4話で、神仏混淆七福神を作ったメンバーが吉祥寺に集まったときにいた場所です。メンチカツやコロッケで有名なサトウ(作中ではすどう)、帽子をいろいろと試着していたのは SHAZBOT、映画館(作中の NEW バウスシアター)は既に取り壊されて ROUND1 になっています。サンロードは自転車をおして歩きましょう。

f:id:KeithYokoma:20171210144056j:plain

吉祥寺駅

サンロード付近で遊ぶために集合した地点です。現在クリスマスシーズン真っ只中ですので、原画売の少女のときのような雰囲気を楽しめますね!

f:id:KeithYokoma:20171210144009j:plain

マルイ:Pancake House

作中では Pancake Home になっていたお店です。マルイの1Fに入っています。反対側には the 3rd Burger があります。

f:id:KeithYokoma:20171210144519j:plain

井の頭公園:弁財天

マルイからならば七井橋通り(一番人通りのあるスタバなどが面している通り)を通って七井橋をわたり、弁財天に向かいます。 この後吉祥寺通りに出たらまっすぐ北に向かいます。途中アニメイト吉祥寺の入っているパルコ(作中時点ではパルコではなくユニクロの向かい側にあった)が右手に見えます。

f:id:KeithYokoma:20171105125352j:plain
井の頭弁財天

青梅街道・都道7号線(五日市街道)分岐点

吉祥寺通りを青梅街道との交差点まで行き左折。西にしばらく行くとジョジョなどの制作を手掛けた会社が右手に見えます。

さらにそこから西へ行くと左車線が斜めに分岐する地点に到達します。

f:id:KeithYokoma:20171210150554j:plain

この地点は11話で宮森の車がドリフトしながら走り抜けていった場所です。

この都道7号線、SHIROBAKOではかなりの頻度で登場します。 落合がカナンスタジオの人と話しをしているところを木佐さんが目撃したのもこの道です。

ちなみに青梅街道をそのまままっすぐ進んで新青梅街道との交差点まで進むと、絵麻ちゃんと井口さんが散歩に来た場所が近くにあったり、ちょくちょく背景にうつるタワー(田無ワター)があったり、 新青梅街道をずっと西へいくと1話で宮森と富ヶ谷がレースをしていた陸橋2つがあったり、ゴスロリさんのオアシスがあったり(現在閉店)します。

柳橋交差点

えくそだすっ!に出てくる交差点です。3人が武蔵野ドームを飛び出してから間もないところで出てきます。作中ではいなげやの方角から青梅街道に向かって逃げていきます。

f:id:KeithYokoma:20171210151333j:plain

今回はここを左折して武蔵境通りを武蔵境駅に向かいます。

いなげや

2期オープニングで宮森の車がグイッと曲がって井の頭通りに出るシーンにうつるいなげやは武蔵境通りと井の頭通りの交差点にあります。

f:id:KeithYokoma:20171210151601j:plain

桜橋

1期オープニングで宮森の車が朝日にむかってシュッと飛んだり宮森が自転車で走っているところなど多々使われています。

武蔵野アニメーション社屋

桜橋を超えてすぐ、現在は老人ホームが建っているあたりが武蔵野アニメーション社屋があった場所なはずです。

f:id:KeithYokoma:20171210152002j:plain

社屋すぐ南の交差点は6話で宮森の姉が絵麻ちゃんを見かけて声をかけようとした場面で使われています。

f:id:KeithYokoma:20171210152055j:plain

TAIRAYA

5話で絵麻ちゃんと宮森が買い物をしたスーパーです。作中ではAIRAYAになっています。

f:id:KeithYokoma:20171210152207j:plain

すきっぷ通り

6話で宮森の姉がきたとき、またタローと平岡が酔いつぶれたいた場所でもあります。今でも日高屋が営業を続けています。

f:id:KeithYokoma:20171210152255j:plain

武蔵境駅

ここも宮森の姉の上京シーンのほか、りーちゃんが舞茸さんの弟子になりたくて「頑張りマスタング!」と食い下がったところでもあります。 駅の西側にあるSWINGビルは木下監督が複葉機にのって飛び去るシーンにも描かれていますね。

f:id:KeithYokoma:20171210153119j:plain

武蔵野プレイス

みーちゃんが宮森と話をするシーン、13話でりーちゃんが宮森と話をするシーン等あります。

f:id:KeithYokoma:20171210152826j:plain

ウルソン

本田さんが転職した先の洋菓子屋さん(作中ではウルリン)です。

f:id:KeithYokoma:20171210152418j:plain

ちなみにこの道を少し言って亜細亜大学の裏手を曲がると油そばで有名な珍々亭があります。

境橋

1話で瀬川さんの家に緊急のカットを取りに行く場面で出てきます。 この場面で宮森が走っていった方角の都道7号線を行くと小金井公園があり、矢野さんと平岡がタイタニックに向かうときに出てくる風景でもあります。 今回はこの逆、吉祥寺方面へ向かいます。

ガスト

境橋の次の信号、関前五丁目の交差点にあります。 9話でずかちゃんのガヤアフレコ後に夕食をとっていたところです。みーちゃんがプリウスを見かけてホイールに見とれている場所でもあります。

f:id:KeithYokoma:20171210153914j:plain

ゴール:松亭

誰もが知る松亭ですね。いい運動をしたので定食を食べても大丈夫なはずです。気をつけて帰りましょう。

f:id:KeithYokoma:20171216104301j:plain

動画

youtu.be

さいごに

最終話、木佐さんの自転車のサドルがシートポストごと外されブロッコリーが刺さっていたのは、一時期すこし話題になった事件をネタにしているのでしょうか。いずれにしても最後の最後完パケてから返してもらうことが出来たようです。最終話といえば、宮森の新幹線が雪で徐行するシーンがありましたが、あれは間違いなくうちの地元のちかくで毎年恒例なので何はなくともすまんッという気持ちで見ていました。

都内にはまだまだいろんな聖地があるようです。行ったことのない場所も多いので、年が明けたらまた巡ってみようと思います。

甘い口溶けのスタウトビールを飲みました

この記事はBeer Advent Calendar 2017の9日目の記事です。

adventar.org

きっかけ

f:id:KeithYokoma:20171208225419j:plain

なにがきっかけでチョコレートビールの存在を知ったのかは忘れてしまいましたが、その後たまたま見かけたアニメでも取り上げられていて、なるほどこれは良さそうと思いアドベントカレンダーの記事にしようと購入しました。 なかなか置いているお店もないのでアマゾンでポチッとお取り寄せ。注文を受けてから瓶詰めしてくれるそうで相当気合が入っています。今回は4本セットの商品を買いました。この記事にはそのうち、Sweet Vanilla StoutとBrown Porterについて書きます。

Sweet Vanilla Stout

f:id:KeithYokoma:20171208230323j:plain

名前の通り、ほんのりバニラの香りがする甘い口当たりのスタウトビールです。もともとスタウトビールが好きで、特に柔らかい感じがある濃い目のスタウトが好みです。 そしてこのSweet Vanilla Stoutは香りもいい😋。最高です。

Brown Porter

写真撮り忘れましたorz

こちらはSweet Vanilla Stoutにくらべるとすこし苦味が強いビールです。コーヒーのような風味が苦味を出していますが、こちらも柔らかい口当たりで飲みやすいです。 コーヒー風味はあくまで風味として楽しめる感じなので、コーヒーが苦手なひとでも飲みやすい気がします。最高です。

おわりに

本当はインペリアルチョコレートスタウト買うぞって思ってたのに、気がついたら同じ醸造所の違うビールを頼んでいました。 酔った勢いでポチッとしてはいけませんね。でも美味しかったので結果よしです。

potatotips #45 で発表してきた

potatotips #45 にて WebView😇😇😇 と題して発表してきました。

speakerdeck.com

概要

ChromeCustomTabs の登場で使い所が限られてきている WebView ですが、法的情報(プライバシーポリシーや規約など)の簡素な静的 HTML を表示するために手軽に使えるため、意外に使う機会があります。ただし、WebView で表示する HTML 内に file:///android_asset/ の中にある別の HTML へのリンクが有ると、Nougat からのセキュリティ仕様によって FileUriExposureException でクラッシュする場合があります。

なぜクラッシュするのか

WebView には WebViewClient というクラスがあり、このクラスの shouldOverrideUrlLoading メソッドをオーバライドすることで、ページ内のリンクを踏んだときにアプリがどのような挙動をするかを決められます。ただしこの WebViewClient の設定は任意のため、WebView に何も設定しないことも可能です。この WebViewClient の有無がみそで、WebViewClient を WebView に設定した場合は shouldOverrideUrlLoading の返り値をもとに挙動が決められますが、WebViewClient が無い場合はリンクを踏んだときに、そのリンクを Uri として適切にハンドリングできるアプリを探しに行きます。ここで Intent に file スキームのリンクを踏んでしまうと、そのリンクが Uri になり Intent に詰め込まれてしまうため、FileUriExposureException が発生するというわけです。

ドキュメントへの記載はあるものの WebViewClient の shouldOverrideUrlLoading メソッドにしか書いていないこと、StrictMode でも検出できるものではありますが、Debug 用途にカスタマイズしている場合設定漏れで検出されなくなることから、地味に気づきにくい問題です。

FileUriExposureException と言うと、アプリが生成したファイルを直接他のアプリに共有しようとして起こるものというイメージがありますが、WebView でも起こりうるということを気に留めておきましょう。

RTL かどうかを判定する

RTL(Right To Left; アラビア語などの右から左へテキスト等をレイアウトする必要のある環境)対応にはいくつかのステップがあります。

単にレイアウトの属性を RTL に対応したもの(gravity や margin、padding や RelativeLayout の各種属性を Left/Right ではなく Start/End)にするだけでも多くの範囲をカバーすることができます。 Drawable resource については Kitkat から autoMirrored という属性が増えました。これを使うことで RTL 向けの画像を作らずとも自動で反転処理をしてくれるようになります。

ここまででおおよそ RTL 対応ができていそうな気がしますが、もう一つ大事な要素があります。それは自分で View をカスタマイズしている場合に必要な対応です。 レイアウト処理を自分で書いたり、Canvas による描画を自分で書いたりなど、様々なカスタマイズの方法があるとおもいますが、ここで LTR(Left To Right; 左から右へテキスト等をレイアウトする環境) を前提にしたコードを書いていると、RTL な環境でうまく動かなくなります。

RTL 環境での処理を LTR と分ける必要がある場合には、Configuration#getLayoutDirectionを使います。ただしこのメソッドは Jelly Bean MR1 からしか使えないため、それ以前のバージョンをサポートするにあたってはサポートライブラリのViewCompat#getLayoutDirectionを使います。帰ってきた値をViewCompat.LAYOUT_DIRECTION_RTLと比較することで、RTL かどうかを判定します。

StateListDrawable の子にあたる Drawable の背景色を Animator で変えてみる

概要

Android Framework に数ある Drawable のなかでも、View の状態に応じて使う Drawable を切り替えることのできる StateListDrawable は多くの人が使っていると思います。ListView のアイテムの背景、ボタンの背景などインタラクションをする View に対して使うことが多いでしょうか。

ところでAndroid の場合、ユーザの指による操作以外にもマウスやキーボードなどの外部入力装置による操作もインタラクションの手段として使えます。外部入力装置を使う場合、いまどこを操作しようとしているかを見せるために、StateListDrawable の state_focused を使って Drawable を切り替えます。

StateListDrawable の各状態で使う Drawable は ShapeDrawable や BitmapDrawable など他の Drawable です。今回は、StateListDrawable の各状態に ShapeDrawable を設定し、state_focused などを考慮しつつ Java や Kotlin のコードから ShapeDrawable の背景を Animator で変えてみようと思います。

<selector>

次のような StateListDrawable を xml で書きます。クリック時には背景を濃いグレーに、フォーカスが当たった時は枠線を描きます。クリック時でかつフォーカスが当たったときは濃いグレーの背景に枠線を描きます。

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_focused="true" android:state_pressed="true">
    <shape android:shape="rectangle">
      <solid android:color="#333333"/>
      <stroke android:width="3dp" android:color="00AAFF"/>
    </shape>
  </item>
  <item android:state_pressed="true">
    <shape android:shape="rectangle">
      <solid android:color="#333333"/>
    </shape>
  </item>
  <item android:state_focused="true">
    <shape android:shape="rectangle">
      <solid android:color="#999999"/>
      <stroke android:width="3dp" android:color="00AAFF"/>
    </shape>
  </item>
  <item>
    <shape android:shape="rectangle">
      <solid android:color="#999999"/>
    </shape>
  </item>
</selector>

Drawable の背景色を変更する

StateListDrawableDrawableContainerの子クラスで、DrawableContainerにはgetCurrentというメソッドがあります。StateListDrawableのような状態を持つものの場合は、現在表示しているものを返してくれるのでこれを使います。

さきほど xml で作った StateListDrawable の子はどれも<shape>ですので、getCurrentメソッドで得られるのもその時の状態で指定している<shape>です。<shape>タグを読み込むと、どの形(四角形、円など)かという ShapeDrawable とどのような背景色や枠線を描画するかという GradientDrawable のふたつが作られます。StateListDrawable#getCurrent()で直接得られる Drawable はGradientDrawableであることに注意しましょう。 そして取り出したGradientDrawablesetColor(int)メソッドで背景色を変えることができます。 あとは、Animator を使えば背景色をアニメーションできます。

fun animateBackgroundColor(view: View, color1: Int, color2: Int, duration: Long) {
  val background = view.background as StateListDrawable
  val animator = ValueAnimator.ofObject(ArgbEvaluator(),
      ContextCompat.getColor(view.context, color1),
      ContextCompat.getColor(view.context, color2))
  animator.duration = duration
  animator.addUpdateListener {
    (background.current as GradientDrawable).setColor(it.animatedValue as Int)
  }
  animator.start()
}