お仕事で極悪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("..."))
も同時に加えるとダメっぽい。