パルカワ2

PerlとRubyとイチャラブ

AndroidエミュレータでのAuto Backup for Appsを検証する

  • Settings > Backup & Reset でバックアップを有効にする
  • バックアップ用にGoogleアカウントにログインしている必要がある
  • adb shell bmgr run
  • データを保存するような動作をする
  • adb shell bmgr backupnow
  • App infoからデータをクリアする
  • adb shell bmgr restore

Auto Backup for Apps | Android Developers

コマンドを実行するとTransport errorというのが出ていて???ってなってたけど、バックアップが有効になってなかった事とバックアップアカウントが設定されていないのが原因だった。

Retrofit2+RxJava2 で リクエストするときに subscribeOn を指定する必要がないようにする

こういう風にRetrofit2を利用してた。

new Retrofit.Builder()
    .client(clientBuilder.build())
    .baseUrl(...)
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build();

APIを叩くコードを書くたびsubscribeOnを指定していてめんどくさかったので調べたらcreateWithSchedulerを利用すればどうにか出来ると知った。

new Retrofit.Builder()
    .client(clientBuilder.build())
    .baseUrl(...)
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
    .build();

便利

お産合宿11に出た

お産合宿にいってきた。

「お産合宿」はデザイナーやエンジニアなどの「クリエイター」という枠にとらわれず、普段は別々の仕事をしているさまざまな職種のスタッフが、所属する部署や職種を飛び越えてチームを作り、自分たちが「もっとおもしろくできる」と思うものを存分に作る、そんな合宿です。
【 #ペパボお産11 】開催決定!応援よろしくお願いします! | お産合宿11 | GMOペパボ株式会社


チームメンバーはminneのマネージャー二人とminneのCTL二人の計四人です。

お産合宿の前には全く開発せずにお産合宿でのみ開発する気持ちでいったら、なかなか大変でしたがそれも含めて楽しかったです。
今の会社に入って3年過ぎて、ついに4年目なのですが、お産合宿は初参加でした。昔は趣味で吉高由里子関連のアレコレをつくっていた僕も今では汚れてしまい、お金がもらえないとつくる力が無になっていたのですが、お産合宿に参加する人たちや作られたものたちを見てるとテンションが上がり、ちょっと作るか…!という気持ちになったので参加してよかったです。次があるなら次はサービス作ってみたいナー

プロジェクトを動かすために必要なAndroid Studioのプラグインを設定する

Preferences -> Build, Execution, Deployment -> Required Plugins

で設定出来た。+を教えて出てきたダイアログがこんなんで、Pluginのところがスクロール出来る。今の今まで、スクロールが出来ることに気づいてなかった………なんてこった…

f:id:hisaichi5518:20170829012010p:plain

設定するとこんな感じで表示される。良さそうなら保存すれば、 .idea/externalDependencies.xmlが作成される。
f:id:hisaichi5518:20170829011758p:plain

あとは .gitignore に .idea/externalDependencies.xmlを除外するようにしておくとよい。

複数のデータソースに同時にアクセスしていい感じにアレしてソレする

  • localSource と remoteSource同時にアクセス。早く返ってきたほうを使う
  • 速度関係なくremoteSourceから値が返ってきたらlocalに値を保存したい
  • localSourceでエラーが出てもログを吐いて、remoteSourceの値を待ちたい
  • 値を使う使わないに関係なく、エラーは起きたらある程度はハンドリングしたい

というのをオペレーターで出来ないものか…?と思って調べてたけど、チームメンバーに「こうやればいいよ」と言われたのがシンプルだった。たしかにな……………

SingleSubject<String> subject = SingleSubject.create();

Single<String> localSource = Single.create(emitter -> {
    Log.i("TEST", "local");
    // emitter.onSuccess("data1");
    emitter.onError(new RuntimeException("local error"));
});

Single<String> remoteSource = create(emitter -> {
    Log.i("TEST", "remote");
    // emitter.onSuccess("data2");
    emitter.onError(new RuntimeException("remote error"));
});

localSource.subscribe(string -> {
    Log.i("TEST", "local source onSuccess");
    subject.onNext(string);
}, Throwable::printStackTrace);

remoteSource.subscribe(string -> {
    Log.i("TEST", "remote source onSuccess");
    subject.onNext(string);
    // local に保存
}, subject::onError);

subject.subscribe(string -> Log.i("TEST", string), Throwable::printStackTrace);

追記:
SingleSubjectだとonSuccessのあとにonErrorがくるとエラーになるので、PublishSubjectなどにしてtake(1) とかを使うといい気がした。

複数のデータソースから値を取り出すのをRxJavaのconcatで実現する場合のエラー処理

blog.danlew.net

複数のデータソースから値を取り出すのをRxのconcatで実現するという記事を見て、なるほど!!と思った。ただ、エラーになった場合どうなるのかわからなかったので確認した。

以下のようなコードの場合は、localSourceのErrorがonErrorにきてremoteSourceのErrorはこない。(というか、そもそもremoteSourceが実行されない)

Single<String> localSource = Single.create(emitter -> {
    emitter.onError(new RuntimeException("1個目のError"));
});

Single<String> remoteSource = create(emitter -> {
    emitter.onError(new RuntimeException("2個目のError"));
});

Single.concat(localSource, remoteSource).subscribe(string -> Log.i("TEST", string), Throwable::printStackTrace);

localSourceの読み込みに失敗したら、remoteSourceのデータを使いたいと思ったので、onErrorReturnとfilterでどうにか出来ないかと思った。これでremoteSourceのErrorがonErrorにくるようになる。ちなみに空文字なのは、RxJavaはnullを許容しないからです。

Single.concat(localSource.onErrorReturn(__ -> ""), remoteSource)
  .filter(""::equals)
  .subscribe(string -> Log.i("TEST", string), Throwable::printStackTrace);

またはObservableにしてempty()を使うというのがコード自体は長くなるがfilterしなくていい(変な仕様を作らなくてよい)ので良い気がした。

Observable.concat(localSource.toObservable().onErrorResumeNext(Observable.empty()), remoteSource.toObservable())
                .first("default")
                .subscribe(string -> Log.i("TEST", string), Throwable::printStackTrace);

もっといい方法ありそう!!! あったら教えてください

追記:
教えて頂いた!Maybe!onErrorComplete() そもそも知らなかった…

io.reactivex.Single.create() でonSuccessしたあとにonErrorを実行するように書いたらどうなるのか

RxJava2の話です。
自分でSingle.create した時についうっかりonSuccessしたあとにonErrorを実行するようなコードを書いた場合どうなるのだろうか?と思ったのでやってみました。

Single<String> single = Single.create(emitter -> {
  emitter.onSuccess("test");
  emitter.onError(new RuntimeException("エラー"));
});

single.subscribe(string -> {
  Log.i("TEST", string);
}, throwable -> {
  Log.i("TEST", "onError");
});

こういうコードだとUndeliverableExceptionが出る。UndeliverableExceptionなので当然onErrorは実行されない。
では、onSuccessが2回実行されたらUndeliverableExceptionが出るのかと思ったけど、そうではないみたい。
以下のコードは 最初のonSuccessが1度実行されて終わる。

Single<String> single = Single.create(emitter -> {
  emitter.onSuccess("test");
  emitter.onSuccess("hoge");
});
single.subscribe(string -> {
  Log.i("TEST", string);
}, throwable -> {
  Log.i("TEST", "onError");
});

qiita.com

これを読んでると single()はonSuccessが2回実行されると死ぬでと書いてるのでRxJava2ではどうなのか確認してみたところ、RxJava2でも同様にエラーになったので同じく2つ目以降の値は流れてきてはいけないものに使うと認識した。

Observable.range(1, 5).single(100).subscribe(i -> {
  Log.i("TEST", String.valueOf(i));
}, Throwable::printStackTrace);

1個で良い場合は、first()を使うとよさそうだった。

Observable.range(1, 5).first(100).subscribe(i -> {
  Log.i("TEST", String.valueOf(i));
}, Throwable::printStackTrace);

追記:
紛らわしい感じだったので、タイトル直した。
複数回呼ばないほうが安心安全っぽいので基本はそうするのが良さそう