Androidで定期的にバックグラウンド処理する場合、従来はPARTIAL_WAKE_LOCKなWakeLockを使う必要がありました。
AlarmManagerでタイマーを仕掛け、タイマーで起こされたBroadcastReceiverがWakeLockでCPUをスリープしないようにしてからServiceを呼んで、Serviceでバックグラウンド処理をし、完了したらBroadcastReceiverが持っているWakeLockを解除してCPUがスリープできるようにする、という流れです。
ここでWakeLockが若干面倒なので処理を簡素化するためにできたのがWakefulBroadcastReceiverです。
公式のトレーニングにも説明が載っています。
WakefulBroadcastReceiverからstartWakefulService()でServiceを起動し、Serviceは処理が済んだらWakefulBroadcastReceiver.completeWakefulIntent()を呼ぶ。
その間はCPUがスリープしないと。
完璧です。
そう思って僕も早速これに置き換えましたが、どうもServiceの処理に時間がかかってしまいます。
もともと2分くらいなのですが、10分とか1時間とかかかっているケースもあります。ただ充電中(開発者オプションで画面付けっぱなし)は2分くらいで済んでいます。
どうも、CPUがスリープしてしまっているように思えます。が、そんなハズはとWakefulBroadcastReceiverのソースを読んでみたところ・・・
wl.acquire(60*1000);
60秒でタイムアウトだそうで。
今回のケースではアウトです。
本当にありがとうございました。
--- 20151029追記 ---
今回はWakefulBroadcastReceiverを取り込んで対処しました。
ソースを自分のプロジェクトにコピペしてpackageとタイムアウト値を変更して使いました。
Apache 2.0なライセンスなので、そこら辺はちゃんとしないといけないですね。
2015年10月28日水曜日
2015年10月27日火曜日
[解決]BOOT_COMPLETEDで起動しない機種があるときはintent-filterに誤りがあるかも
AndroidManifestにこう書いていたら、Zenfone5の電源投入時にonReceiveが呼ばれませんでした。
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
・・・というか、このやり方なら「電源投入時に起動する」という設定を覚えておく必要がないのですね。
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
カテゴリ指定を取ってこう書いたらonReceiveが呼ばれるようになりました。
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
公式のトレーニングにもそう書いてありますね。
しかも最初は呼ばれない(enabled="false")ようにして、ユーザが明示的にONしたときにPackageManager経由で有効にする、というのが正しいやり方のようです。
・・・というか、このやり方なら「電源投入時に起動する」という設定を覚えておく必要がないのですね。
2015年7月16日木曜日
[解決] やっと繋がった!MediaPad T1 7.0がWi-FiのSSIDすら見つけてくれない時の対処方法
母親に貸そうと思っていたAndroidタブレットが使い物にならなくなったので、つい新しいのを買ってしまいました。
ちょうどガジェット系のニュースに「1万円タブレット」として出ていた「MediaPad T1 7.0」です。
職場で休み時間にセットアップしたときはZenFone 5のWi-Fiテザリングを使ったのですが、自宅でWi-Fi接続しようとして困りました。
SSIDが見つからないのです。
ご近所のと思われるSSIDはいくつも見つかるのに。
そういえば以前から、Windows 8.1タブレットのMiix 2 8も繋がらなくなっていました。
さほど使っていなかったのと、ネット閲覧程度ならZenFone 5のBluetoothテザリングで十分だったのでそのうち調べようと後回しになっていたのです。
と言うわけでググったら速攻で見つかりました。
無線LAN親機に設定したチャンネルが問題だったのです。
このように「13チャンネル」(ch 13)をメインで使っていたのですが、Miix 2 8はこのチャンネルが見えないそうです。(倍速モードのチャンネルは9)
「11チャンネル」を使うようにしたら、Miix 2 8もMediaPad T1 7.0もちゃんとSSIDを見つけてくれて無事に接続できました。
◇◇◇
ちなみにこの設定は元々「自動」でしたが、大きなファイルをダウンロードするなど負荷が上がるとパソコンやスマホの通信が切れてしまうという障害がありました。
混雑しているからと自動でチャンネルを変更してしまうために起こる現象なので固定にしたのです。その際にご近所と被りづらそうな大きめの数字に設定したのが敗因でした。
分かってしまえば簡単ですが、結構長いことハマりました。
ちょうどガジェット系のニュースに「1万円タブレット」として出ていた「MediaPad T1 7.0」です。
職場で休み時間にセットアップしたときはZenFone 5のWi-Fiテザリングを使ったのですが、自宅でWi-Fi接続しようとして困りました。
SSIDが見つからないのです。
ご近所のと思われるSSIDはいくつも見つかるのに。
そういえば以前から、Windows 8.1タブレットのMiix 2 8も繋がらなくなっていました。
さほど使っていなかったのと、ネット閲覧程度ならZenFone 5のBluetoothテザリングで十分だったのでそのうち調べようと後回しになっていたのです。
と言うわけでググったら速攻で見つかりました。
無線LAN親機に設定したチャンネルが問題だったのです。
このように「13チャンネル」(ch 13)をメインで使っていたのですが、Miix 2 8はこのチャンネルが見えないそうです。(倍速モードのチャンネルは9)
「11チャンネル」を使うようにしたら、Miix 2 8もMediaPad T1 7.0もちゃんとSSIDを見つけてくれて無事に接続できました。
◇◇◇
ちなみにこの設定は元々「自動」でしたが、大きなファイルをダウンロードするなど負荷が上がるとパソコンやスマホの通信が切れてしまうという障害がありました。
混雑しているからと自動でチャンネルを変更してしまうために起こる現象なので固定にしたのです。その際にご近所と被りづらそうな大きめの数字に設定したのが敗因でした。
分かってしまえば簡単ですが、結構長いことハマりました。
2015年7月10日金曜日
[解決] iOSの実行時バージョン判定による分岐は3種類
昨日のエントリでも使いましたがiOSのアプリ開発ではバージョンを判定して処理を分けることが時々あります。
で、ググると3種類出てきてどれを使おうか軽く悩みました。
SDKに登場した順に並べるとUIDeviceを使うのが一番古く、NSProcessInfoはiOS8で初登場だそうです。
で、ググると3種類出てきてどれを使おうか軽く悩みました。
SDKに登場した順に並べるとUIDeviceを使うのが一番古く、NSProcessInfoはiOS8で初登場だそうです。
- [UIDevice currentDevice].systemVersion
- NSFoundationVersionNumber
- NSProcessInfo
現在開発中の業務アプリはiOS7向けなのでNSProcessInfo以外を使うこととなり、中でも新しいNSFoundationVersionNumberを使うようにしました。
実装はここを参考にしました。
2015年7月9日木曜日
[解決] Xcode 6.4のMaster-DetailテンプレートがiOS 7.1のiPadで動作しない不具合の回避
こちらと同じ現象で困り、別の方法で回避しました。
Xcode6でiOS7向けにMaster-Detailアプリを作る時の注意点 - 技術はメシのタネ
要は、iOS8にしか存在しないdisplayModeButtonItemにアクセスしているから悪いのです。
と言うわけで2箇所(AppDelegate.mとMasterViewController.m)ある当該部分をiOS8以前は実行しないよう、このようにif文で囲みました。
if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1) {
navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem;
これで良いのか悪いのかがサッパリ分からないのでスッキリしません。
たとえばこのような疑問が残ります。
要は、iOS8にしか存在しないdisplayModeButtonItemにアクセスしているから悪いのです。
と言うわけで2箇所(AppDelegate.mとMasterViewController.m)ある当該部分をiOS8以前は実行しないよう、このようにif文で囲みました。
if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1) {
navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem;
}
これで良いのか悪いのかがサッパリ分からないのでスッキリしません。
たとえばこのような疑問が残ります。
- バージョンで見るのが正しいのか?フィールド(Selector?)の有無で判断するほうが良いのではないか。
- 比較に使っている定義がiOS7.1までしかない。コードとしては「7.1より大きいとき」となるので万が一7.2などが出たら動かない(出ないだろうけど)
- iOS7以下の時に何か実行しなければならない処理はないのか。
気にはなりますが、回避はできたのでひとまず良しとします。
2015年7月2日木曜日
UINavigationControllerにTab Barを置くときの注意事項
今作っている業務アプリは、iPadの横向き専用です。
UISplitViewControllerのMaster/Detail両方ともTop BarとBottom Barを表示しています。
UIにチカラは入っていないので、できるだけそれぞれのBarにボタンを足してアレコレしてしまっているのです。
ところで今回画像のサムネイル表示をしようとして、Detail側にTab Barを追加しようとしました。
何パターンか試したのですが
・DetailとしてUINavigationControllerではなくUITabBarControllerを繋げる
→× NavigationのBottom Barが消える(当たり前)
・DetailのUINavigationControllerからUITabBarControllerを繋げる
→× Tab Barの上にNavigationのBottom Barが重なって動かせない
・DetailのUINavigationControllerから繋がったUIViewControllerにUITabBarを配置する
→○ とりあえず希望の動作になった。
場所はConstraintsで対応。両端に伸ばすため左右のSpaceがSuperViewの「-16」なのは少し不思議。
とりあえず。
UISplitViewControllerのMaster/Detail両方ともTop BarとBottom Barを表示しています。
UIにチカラは入っていないので、できるだけそれぞれのBarにボタンを足してアレコレしてしまっているのです。
ところで今回画像のサムネイル表示をしようとして、Detail側にTab Barを追加しようとしました。
何パターンか試したのですが
・DetailとしてUINavigationControllerではなくUITabBarControllerを繋げる
→× NavigationのBottom Barが消える(当たり前)
・DetailのUINavigationControllerからUITabBarControllerを繋げる
→× Tab Barの上にNavigationのBottom Barが重なって動かせない
・DetailのUINavigationControllerから繋がったUIViewControllerにUITabBarを配置する
→○ とりあえず希望の動作になった。
場所はConstraintsで対応。両端に伸ばすため左右のSpaceがSuperViewの「-16」なのは少し不思議。
とりあえず。
登録:
投稿 (Atom)

