前人未踏の領域へ Androidアプリ開発編

Androidアプリ開発に関する調査メモ置き場。古い記事にはアプリ以外も含まれます。

Firebase AnalyticsでBigQueryを使った場合の調査メモ

挙動に関して不明な箇所があったので実際にやってみたメモ

  • DebugViewはユーザープロパティの削除が反映されない(BigQueryには反映されている)
  • DebugViewはユーザープロパティの追加が反映されないことがある(BigQueryには反映されている)
    • 連続して2つセットしてもDebugViewには1つしか出ないなど
  • 比較的すぐにBigQueryに結果が反映される。
    • 但しプレビューテーブルへの反映は即時ではなさそう
  • user_properties, event_paramsの展開にはUNNESTを使う
  • BigQueryのクエリー価格は $5.00 per TB 毎月 1 TB まで無料
    • SQLを書くと使用容量が分かる
    • 1クエリーは30kb 〜 500kbくらい(対象データ量、取得カラム数により増減)
    • テスト環境なら惜しまずクエリー投げて問題ない
  • 一度セットしたユーザープロパティはアプリを終了しても送信される
    • なのでログイン者情報などはログイン時にセットすればOK
  • アプリをアンインストール後に再インストールするとセットしていたユーザープロパティは消える。

RecyclerView内のアイテムが表示されたタイミングを取得する

課題

RecyclerView内のあるViewTypeのアイテムが表示されたタイミングでImpressionイベントを計測したい。

対応

RecyclerView.Adapter.onViewAttachedToWindow() メソッドをオーバーライドする。

    override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
        super.onViewAttachedToWindow(holder)

        if (holder.itemViewType == TYPE_HOGE) {
            if (BuildConfig.DEBUG) {
                Log.d(TAG, "onViewAttachedToWindow called")
            }
            sendGoogleAnalyticsEvent()
        }
    }

注意点

AdapterのnotifyDataSetChanged()が呼ばれると画面表示中でもに見えても実際には再描画が発生してonViewAttachedToWindowが呼ばれてしまう。 notifyItemChangedを使い、かつRecyclerViewのitemAnimatorをnullにしておく必要がありそう。

感想

これまでは ViewTreeObserver.onPreDrawListener を使っていたけれど、ちゃんとremoveしてあげないと メモリーリークの心配があったりonBindViewが一度しか呼ばれないようなケース(再利用が発生しない) ではそもそもonPreDrawListenerがセットできないなど問題があったが、これでまるっと解決した気がする。

自前でRipple Effectを呼ぶ

課題

Viewに android:foreground="?android:attr/selectableItemBackground" を定義しているが、プログラム上から呼び出して使用したい。

対応

RippleDrawableのstateを変更することでエフェクトが発生するのでstateを変更してあげれば良い。 以下のサンプルはview.foregroundに RippleDrawableが定義されていることを前提としている

if (Build.VERSION.SDK_INT >= 23 
  && view.foreground isRippleDrawable) {
        val rippleDrawable: RippleDrawable = view.foreground as
                                RippleDrawable
                        rippleDrawable.state = arrayOf(
                            android.R.attr.state_pressed,
                            android.R.attr.state_enabled
                        ).toIntArray()
                        holder.itemView.postDelayed({
                            rippleDrawable.state = IntArray(0)
                        }, 200)
                   }

ダブルタップ対応でonClickListenerではなくonTouchListenerを使おうとしたときに必要になった。
view.backgroundの場合はSDK_INTは21以上から対応しているかと。

参考

How to trigger ripple effect on Android Lollipop, in specific location within the view, without triggering touches events? - Stack Overflow