Titanium Advent Calendar 2014の6日目です。
岩手でTitaniumを推進しているチイキットの伊藤です。Titanium界隈の巨人達がいる中で大変恐縮なのですが、初歩的なAndroidのバッググラウンド処理について書いていきます。
やりたいこと
とてもシンプルで何秒、何分ごとに起動し、
条件をチェックして、条件が満たされている場合処理する、しない場合処理しない感じにします。
例えば、ニュースサイトからバックグラウンドで自動でデータを取得し、バックグラウンドに1時間立っていたら、ニュースを取得し、更新された記事を保存するような感じで使えると思います。
※今回はデータの保存まではやりません。。。
- Androidでバックグラウンド処理
- 時間+αな条件での起動
- ボタンを押したらバックグラウンド処理が停止・再開
ログがこんな感じ
ソースはこちらになります
環境はTitanium SDK 3.4.1.GAでAlloyつかってます。
バックグラウンド処理するには
serviceを使います。詳しいことを書くとボロがでるので、
こちらの公式ドキュメントを御覧ください。
http://docs.appcelerator.com/titanium/3.0/#!/api/Titanium.Android.Service
こちらの順番で
- tiapp.xmlにserviceを使うことを追記
- service.jsにバックグラウンドで処理することを記載
- index.jsにサービスの起動・バックグラウンドの検知を書く
tiapp.xmlにserviceを使用する設定を追加する
service.jsというファイルをServiceとして実行し、指定された間隔(interval)で起動するように設定します。
service.jsファイルはapp/assets配下に置く設定になります。
<android xmlns:android="http://schemas.android.com/apk/res/android">
<services>
<service type="interval" url="service.js"/>
</services>
</android>
service.jsにバックグラウンドで処理することを記載
今回はAlloy.Globalsに以下の変数を用意し、
「サービスが処理中じゃない」 かつ 「バックグラウンドに入っている」 かつ 「以前処理した時間より10秒たっている」場合に処理をするように記載しました。
Alloy.Globals.updateNow = false;
Alloy.Globals.activeFlg = true;
Alloy.Globals.updateOften = 10000;
処理中はAlloy.Globals.updateNowの変数をtrueにして処理が重複しないようにしています。
今回処理は記載していませんが、処理が終わったタイミングで、終了時刻を登録し、
Alloy.Globals.updateNowもfalseに変更しています。
Ti.API.info("service is running");
Ti.API.info(to_hhmi(Alloy.Globals.lastClosed));
Ti.API.info("service autoUpdate:" + Alloy.Globals.autoUpdate);
Ti.API.info("service activeFlg :" + Alloy.Globals.activeFlg);
// 現在時刻
var now = new Date();
if (!Alloy.Globals.updateNow
&& !Alloy.Globals.activeFlg
&& (now.getTime() - Alloy.Globals.lastClosed.getTime() > Alloy.Globals.updateOften)) {
Ti.API.info("============================");
Ti.API.info("service Start!!!!");
Ti.API.info("============================");
Alloy.Globals.updateNow = true;
//データ取得等の処理を記載する
//処理終了の時刻を登録
Alloy.Globals.lastClosed = now; // データ取得時刻を保存
//処理中に再度サービスの処理が起動されないようにするため
Alloy.Globals.updateNow = false;
}
index.jsにサービスの起動・バックグラウンドの検知を書く
アプリが起動したタイミングでserviceを起動し、
activityにアプリがバックグラウンドにいるのか、起動している状態なのかを検知するイベントをしこんでいきます。
//Activityのライフサイクルに応じてイベントを設定
$.index.addEventListener("open", function () {
Ti.API.info("open");
Alloy.Globals.activity = $.index.activity;
Alloy.Globals.page = "index";
Alloy.Globals.activeFlg = true;
Alloy.Globals.activity.addEventListener("resume", function(d) {
Ti.API.info("************************ Activity was resumed(再開したよ) ************************");
Ti.API.info(Alloy.Globals.page);
Alloy.Globals.activeFlg = true;
Ti.API.info("activeFlg: true");
Ti.API.info(Alloy.Globals.activeFlg);
});
Alloy.Globals.activity.addEventListener("pause", function(d) {
Ti.API.info("************************ Activity was paused(バックグラウンドにはいったよ) ************************");
Ti.API.info(Alloy.Globals.page);
Ti.API.info(Alloy.Globals.activeFlg);
if(Alloy.Globals.page == "index" && Alloy.Globals.activeFlg ){
Alloy.Globals.activeFlg = false;
// アプリが閉じた時の時間を保存
Alloy.Globals.lastClosed = new Date();
Ti.API.info("lastClosed: " + to_hhmi(Alloy.Globals.lastClosed));
}
});
Alloy.Globals.activity.addEventListener("destroy", function() {
Ti.API.info("Activity was destroied");
Ti.API.info(Alloy.Globals.service);
Ti.API.info(Alloy.Globals.serviceIntent);
});
// サービスを起動(Androidのみ)
if (OS_ANDROID && Alloy.Globals.service == null) {
Ti.API.info("************************ Service Start ************************");
var intent = Titanium.Android.createServiceIntent({url: "service.js"});
intent.putExtra("interval", Alloy.Globals.serviceOften);
var service = Titanium.Android.createService(intent);
service.start();
Alloy.Globals.serviceStatus = true;
Alloy.Globals.service = service;
Alloy.Globals.serviceIntent = intent;
$.index.addEventListener('android:back', function(){
var intent = Ti.Android.createIntent({
action: Ti.Android.ACTION_MAIN
});
intent.addCategory(Ti.Android.CATEGORY_HOME);
Ti.Android.currentActivity.startActivity(intent);
});
}
});
注意する事として、Android特有のbackボタンを押したときにserviceがdestroyされてしまうため、backボタンを押したときにホームボタンと同じ動作をするよう変更しています。
こちらの記事を参考にさせて頂きました。
もう1点たしか画面遷移したタイミングで、activityがpauseされるため、
バックグラウンドにいるのか、画面遷移したのかわからない状態になります。
その場合は、Alloy.Globals.pageで画面遷移する前にpageを変更するのを前回思いつきましたが、もっと良いやり方があるかと思いますので探してみてください。
完成
まとめ
バックグラウンド処理はたまに使用することがあるので、
いままでやったことをまとめることができてよかったです。
ほんとは、yagi さんの言っていたfirebaseで何かやってみたかったのですが、、
次は
明日は同じくチイキットの @s4shiki さんです。いやー岩手熱いですね〜!
よろしくお願いします!