eaglesakuraの技術ブログ

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

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に移行するとハマりそう

Android Emulator(KVM/Ubuntu)でサウンドを有効にするとノイズが乗ることに対する対策

問題点

コマンドラインからサウンド無効で起動する

# ついでにCold Bootしたければ -no-snapshot オプションでできる
emulator @your_avd_name -no-audio -no-snapshot

Desktop Entryにすることで簡単に起動

[Desktop Entry]
Name=Android Emulator
Exec=/path/to/emulator @Default -no-audio -no-snapshot
Terminal=false
Type=Application
Icon=/path/to/icon/android-emulator.png
Categories=Development;Android;Emulator
StartupNotify=false

Android エミュレータのAMD CPU(Hyper-V)サポートの所感

公式情報

android-developers.googleblog.com

  • 書いてあるとおり、 Windows Hypervisor Platform を有効化しないと起動できない
  • Hyper-Vを有効化しているだけだと、Hypervisorは有効化してない場合があるので注意

動作の感想

  • ちゃんとDocker for Windows環境と共存できる
  • Trident3(i7-8700, RAM32GB、Windows10 Pro)で動作した
  • 動作が緩慢
    • 正直、 HAXM とか KVM(Linux) で動作したほうがキビキビ動く
    • 無理して使うようなものでは無いが、あると便利という感じ

システムレイヤーにOpenGL対応Viewを追加する

Manifest設定

  • システムレイヤーへの描画は専用のPermissionがある
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

WindowManagerでViewを登録

  • レンダリング用のViewとタップ用のViewを分けると設計が楽になる場合がある
    • SurfaceViewは軽量だが、View移動ができない
      • OpenGL側でViewportを調整してあげると良い
    • Viewを移動するならTextureViewが良い
// レンダリング用のフラグ
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
        // レイアウトの幅 / 高さ設定
        WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT,
        // レイアウトの挿入位置設定
        WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
        // ウィンドウ属性
        // TextureViewを利用するには、FLAG_HARDWARE_ACCELERATED が必至となる。
        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
                //
                | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_FULLSCREEN
        ,
        // 透過属性を持たなければならないため、TRANSLUCENTを利用する
        PixelFormat.TRANSLUCENT);
// Viewの位置はmarginで調整する
params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;


windowManager.addView(hogeView, params);
// システムレイヤーのView位置を移動する
WindowManager.LayoutParams params = (WindowManager.LayoutParams) hogeView.getLayoutParams();
synchronized (updateRunner) {
    params.x = reqX;
    params.y = reqY;
    params.width = reqW;
    params.height = reqH;
}
windowManager.updateViewLayout(hogeView, params);