お仕事で極悪Androidアプリを改修していて、 今日得た知見をば。
getTextSize/setTextSize
あるActivityの画面で、
本文とボタンのtext sizeを揃えようとして、
TextView#getTextSizeしてからsetTextSizeしたら、
大きくなるんですよね。何でだろう、調べると、
TextView#getTextSizeとsetTextSizeのデフォルト単位が違う
のだそう。びっくりです。
| 1
 |  | 
というように、単位を明示する必要があるそう。
サイズ自動調整TextView
TextViewで、指示通りに改行位置を固定しようと思って。
指示中の、禁則処理に失敗しているところも含めて忠実に再現しようと。
そのためにはtext sizeを随意にせねばならず。
【Android】横幅に合わせてテキストサイズを調整するTextViewそのままで上手く行きました。
あーでもonLayout()の最初の引数changedがtrueの時だけ
resize()すればよかとです。
今はAutosizing TextViewsというのがあるそう。 ただ、API 26からなのでまだなかなか使えないでしょうか。
onLayout後の値の取得
上記のようにtext sizeを変えてから、
その結果のtext sizeに合わせて他のViewのtext sizeを
決定しようとすると、
onLayout()が呼ばれ終わってからでないと
目的の値が取得出来ないんですね。
そこで、
How to know when an activity finishes a layout pass?
にあるように、
myView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {...});
とすれば良いです。
補足
RobolectricでUnit Test書いてたら、
このclass、testが終わらないんです。
何でかなー、とbreakpointで追ってみると、
延々とonGlobalLayout()が呼ばれ続けてるんですね。
えーっと思って。
RxJavaHooks.setOnIOScheduler(s -> Schedulers.immediate());
しても、
ShadowApplication.runBackgroundTasks();
しても効き目はなく。
androidでheightやwidthが0になって取得できない時
を見ると、用が済んだらすぐremoveするんですね。そっか。
というわけで、Android SDKのversionによって分けて、
removeOnGlobalLayoutListener(this)と
removeGlobalOnLayoutListener(this)でremoveするように
したんですけど、今度はthisが効かない。
なるほど、lambdaだとthisは外側のclass instanceになるんですね。
じゃぁっていうんでlambda自体をListener instanceとして名前付けて、
lambdaの中でthisじゃなくてその名前で参照しようとしたんですが、
might not have been initializedとか言われ、
nullで初期化すると今度はeffectively finalじゃないと言われて、
うー、とか思って仕方なく諦めて、
初めてlambdaを解いてinner classの記述に戻しました。
Rx Androidにmaxはない?
探したんですけど見つからなかったので自分で集計しました。
| 1 2 3 4 5 6 |  | 
TextViewで白枠
ある段落を白枠で囲って欲しいと言われました。
調べると、[android]xmlで枠を指定するというのがあり、
それ用のdrawable XMLを作ってやってandroid:background="@drawable/..."で、
それを指定すれば、望み通りのものが得られました。
背景色は、これも書いてありますが#00ffffffで透明になります。
| 1 2 3 4 5 6 7 8 9 10 |  | 
Robolectricで次のActivityへの遷移の確認
shadowOf(activity).peekNextStartedActivity()でIntentを取得、
getComponent().getClassName()が目的のclass nameかをassert。
| 1 2 3 |  | 
Local PushでNotification
Local PushでNotificationをして欲しい、と言われました。
調べてみると、要するに、
AlarmManagerにPendingIntentをsetして、
それがset時の引数のUnix Time(millisec)になると、
これもset時引数のBroadcastReceiverの子classの
onReceive(context, intent)が呼ばれるので、
そこでNotificationManager.notify()をする、と。
AndroidのNotificationについては、 sample applicationを作って色々と試してみました。
- uninstall/端末再起動すれば登録済みのalarmは解除される
- 多重登録してもPendingIntent.FLAG_UPDATE_CURRENTなら最後のNotificationに上書きされる
- 過去の時日のalarmを登録するとすぐNotifyされてしまう
- 機種によっては挙動が違う(Huaweiでは、アプリが起動していない時/Sleep時にAlarmを発動させるには「保護されたアプリ」でないとならない、等)
- 長いtextは全文出ないで端折られる。出したいなら、.setStyle(new NotificationCompat.BigTextStyle().bigText("..."))する。但し.setBigContentTitle(intent.getStringExtra("..."))も同時に加えるとダメっぽい。