eaglesakuraの技術ブログ

技術的な話題とか、メモとか。

QRコードをスキャンする仕様で注意すべきこと

QRコードもカメラも物理デバイスである

  • QRコードは対象物の物理サイズにも留意して作成する
  • 小さすぎると、カメラに映ってもオートフォーカスが正常動作しない場合がある
    • レンズが汚れていると更に辛い
  • フロントカメラは概ね低スペックなので、バックカメラよりも気を使う

実例

  • Nexus9のフロントカメラで18mm角だとスキャンに成功する
  • 16mm角前後だとスキャンに成功する個体・失敗する個体に別れ始める

今後のために

  • 物理的な大きさと距離について、無制限ではないという点に留意して仕様を考える

VIVITA社に転職しました

FROM

以前のエントリーの通り、8月31日で TOPGATE社 を退職しました。

TO

9月1日から、 VIVITA 所属となり、子どもたちがアイディアを形にするための環境づくりを行います。

Androidアプリ開発やサーバー開発といった形で参加する予定です。

ほしいものリスト

(/ω・\)チラッ

http://amzn.asia/66X0Vi3

CIや開発時のビルドタスク管理にfastlaneを導入した

導入前

  • shellスクリプトを必要に応じて書いていた
  • どういうビルドタスクやスクリプトがあるのか、ドキュメントが面倒だった

導入した理由

  • ビルドタスクの一覧性を担保できる
    • fastlane list でタスク一覧が表示される
    • タスクを分類できる
      • fastlane platform_foo task_bar
  • Androidに対応している
    • Gradleタスクは簡単に実行できる
    • bundle, apkのアップロードが簡単に行える
  • 内部でシェルを実行できる
    • どうしても移行が難しいタスクは、内部でシェルをkickすれば良い

導入後の問題点

  • fastlaneを導入しなければならない
    • rubyやbundleと一緒に導入なので、開発しているOSによっては制限がある
  • rubyを覚えなければならない
    • 慣れ
  • 開発 / ビルド用のDocker Imageが300MB程度大きくなる

coroutines 0.24.x runBlockingの仕様変更と対策

変更されたこと

  • runBlockingがUIスレッドからの呼び出しで例外を投げるようになった
    • UnitTestの内部とかで使ったり、無理矢理coroutinesのChannelとかを待ち合わせる用途に使えなくなった
  • 特にJVMでのUnitTestで使ってたので、全部死んだ
// この呼び出しはすべて例外となる
// 23.x系列までは使える
// 24.x系列からは駄目

@Test
fun testHogeFuga() = runBlocking { /* do something */ }

runBlockingの仕様変更に関するissue

issue Support runBlocking for UI Tests

  • コレは意図した変更なので、多分不可逆じゃないかな、とは思う
  • coroutineの処理実装から考えると、特定のシングルスレッドをブロックするのは好ましくない
    • 待機しているcoroutineの処理ブロックが回らなくなる

解決方法

// 最初に呼び出す
init {
    System.setProperty(BLOCKING_CHECKER_PROPERTY_NAME, BLOCKING_CHECKER_VALUE_DISABLE)
}
  • もしくは0.23.x系列までを使用する
  • もしくはUIスレッド対応のrunBlockingを用意する
  • さらに面倒をするなら、BlockingCheckerを自前で実装してそちらを使うように迂回させる
    • この方法は用意されてるけども面倒なのでskip

CoroutineScope.coroutineContextが非推奨

  • suspendブロック内のthis.coroutineContextが非推奨になった
  • トップレベルプロパティとして kotlin.coroutines.experimental.coroutineContext が生まれているので、それを利用する

Huawei P20 Proの所感

購入 / 選定理由

  • 会社に開発端末(普段使いを兼ねる)を返却するにあたり、新規に端末が必要になった
  • 選定で重視した点
    • ARCoreが使用できる
    • 基本スペックが良い
    • カメラ性能が良い
  • 端末サイズは問わない
    • 今まではサイコンにする兼ね合いからXperia Compact系を選定していた
    • XZ5Compactをサイコンとして使用すれば問題ないので、旅の途中での写真撮影が快適な端末を選ぶことにした

妥協点

  • SDCardが使用できない
  • 容量が128GBなので、不安が残る

誤算

  • Goolge Launcherが使用できない
  • Huawei標準アプリがやたらと自己主張が激しい
    • まあ、それがAndroidなので、しょうがない

TOPGATE社を退職します

今日社内で情報が公開されましたが、2010年から勤めていた TOPGATE社 を8月末で退職することとなりました。

トップゲートにいた7年10ヶ月

IT業界としては、かなり長く居たかと思います。

入社時点からAndroidがやりたくて転職して、基本的にはずっとAndroidをやらせてもらえていました。

案件をこなすうちに登壇を経験したり、炎上を経験したり、執筆を経験したり、炎上を経験したり、 Google Cloud Platform に関する知識を身につけたりして、有意義に過ごさせてもらったかと思います。

受託中心の会社だからか、Android界隈に優しい人が多いからか、開発に関わる知人が増えたのも良かったです。

なお、入社時点〜退職時点で年収は2倍以上にアップしました。

初めて彼女ができて、その彼女と結婚して、マンション買って、子供2人生まれて育てているのもTG社に所属している間に経験しているので、自分の青春時代てきな思い入れはかなりあります。

退職を決意した理由

一番の理由はAndroidを含むモバイルの案件がなくなってしまったことです。

TG社は受託が主な開発業務となりますが、Androidを含むモバイル案件が減ってきたので、モバイル関連の仕事を行えなくなってきました。 正確には、「大きくなってきた組織の従業員を食わせていけるだけの規模で、なおかつ十分な収益を見込める案件」が減ってきたので、時代の流れかもしれませんね。

もう一つの理由は、自分の業務内容に金勘定業務が大幅に増えたことです。 プロジェクトに関する見積もりや勘定仕事は今までもある程度やっていましたが、それ以外の管理(自分や部下、プロジェクトを横断した売上管理)業務が最近は多くなっていました。

まだ開発者として、スペシャリストを目指したいので、少し自分の方向とズレてきた感じがありました。

もっといろんな理由

従量課金制です。

摂取するアルコールの量に比例してアンロックされます。

次の行き先

コレを書いている7月末時点でまだ未確定です。

色々な方面、いろいろな方々からありがたいお話を頂いているので、7月・8月にかけて会社見学とか面接とかすすめるつもりです。

既婚者で子供がいるので、 ライフワークバランス収入仕事の面白さ ほかいろいろを天秤にかけている感じです。

たくさんの方に気にかけていただき、無事に次の働き口を見つけました。

連絡をくれた方々、本当にありがとうございました。

プロ無職するの?

蓄えもアルバイトもありますが、 保育園を追い出されると大変なのでアマ無職です。

こんなバイトしない?

HeyHey!! ワタシ、お金、大好きよ!! 副業も請けてるのよ!!

Twitter のDMか、Facebookにてお仕事待ってます!

最後に

トップゲートの皆さん、本当に長い間ありがとうございました。

Android Navigation Componentsのファーストインプレッション

本当に動くの?

  • AS3.2.x系のNavigation Componentsは不安定で、だいたいNavigation Editorが正常動作しなかった
  • AS3.3.x系でNavigation Components自体がExperimental機能として隠し扱いになった
  • 今後もしばらくは不安定だと思う
    • 末永く頑張っていただきたい

Activityの移行

  • NavHostFragment をレイアウトに仕込むだけ
lass MainActivity : AppCompatActivity() {

    private val navHostFragment
        get() = supportFragmentManager.findFragmentById(R.id.NavigationHost) as NavHostFragment

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        MainActivityBinding.inflate(layoutInflater).also {
            it.setLifecycleOwner(this)
            setContentView(it.root)
        }
    }

    override fun onSupportNavigateUp(): Boolean = navHostFragment.navController.navigateUp()
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <fragment
            android:id="@+id/NavigationHost"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/main" />
    </LinearLayout>
</layout>

Fragment側の移行

  • 特にすることはない
  • と思いきや、Layoutを見てわかるとおり、Navigation ComponentsはNested-Fragmentとして動作する
  • Fragment.startActivityForResult() の戻り値が取得できない
  • Runtime PermissionのrequestPermission()は動作する

FragmentXを使用する

  • FragmentActivity.startActivityFromFragment() というヘルパーが追加されている
  • これを呼び出すことで、onActivityResult()がハンドリングできる
// こんな感じ
activity!!.startActivityFromFragment(this, intent, REQUEST_SHOW_SETTINGS)

スプラッシュ画面のように、前画面に戻らせたくない場合

  • 基本的にはBackStackに詰まれるので、戻ることになる
  • Actionの app:popUpTo オプションを指定する
        <action
            android:id="@+id/first_to_second"
            app:destination="@id/secondFragment"
            app:popUpTo="@id/main" />

ハマりそうな

  • Nested-Fragment前提で作ってないClass郡をNavigation Componentsに移行するとハマりそう