Edited at

TitaniumでAndroidのバックグラウンド処理

More than 3 years have passed since last update.

Titanium Advent Calendar 2014の6日目です。

岩手でTitaniumを推進しているチイキットの伊藤です。Titanium界隈の巨人達がいる中で大変恐縮なのですが、初歩的なAndroidのバッググラウンド処理について書いていきます。


やりたいこと

とてもシンプルで何秒、何分ごとに起動し、

条件をチェックして、条件が満たされている場合処理する、しない場合処理しない感じにします。

例えば、ニュースサイトからバックグラウンドで自動でデータを取得し、バックグラウンドに1時間立っていたら、ニュースを取得し、更新された記事を保存するような感じで使えると思います。

※今回はデータの保存まではやりません。。。


  • Androidでバックグラウンド処理

  • 時間+αな条件での起動

  • ボタンを押したらバックグラウンド処理が停止・再開


こんな感じの作ります


ログがこんな感じ


ソースはこちらになります

環境はTitanium SDK 3.4.1.GAでAlloyつかってます。


https://github.com/ganezasan/AlloyAndroidBackground.git



バックグラウンド処理するには

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配下に置く設定になります。


tiapp.xml

    <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.js

Alloy.Globals.updateNow = false;

Alloy.Globals.activeFlg = true;
Alloy.Globals.updateOften = 10000;

処理中はAlloy.Globals.updateNowの変数をtrueにして処理が重複しないようにしています。

今回処理は記載していませんが、処理が終わったタイミングで、終了時刻を登録し、

Alloy.Globals.updateNowもfalseに変更しています。


service.js

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にアプリがバックグラウンドにいるのか、起動している状態なのかを検知するイベントをしこんでいきます。


index.js

//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ボタンを押したときにホームボタンと同じ動作をするよう変更しています。

こちらの記事を参考にさせて頂きました。


http://selfkleptomaniac.org/archives/2128


もう1点たしか画面遷移したタイミングで、activityがpauseされるため、

バックグラウンドにいるのか、画面遷移したのかわからない状態になります。

その場合は、Alloy.Globals.pageで画面遷移する前にpageを変更するのを前回思いつきましたが、もっと良いやり方があるかと思いますので探してみてください。


完成


まとめ

バックグラウンド処理はたまに使用することがあるので、

いままでやったことをまとめることができてよかったです。

ほんとは、yagi さんの言っていたfirebaseで何かやってみたかったのですが、、


次は

明日は同じくチイキットの @s4shiki さんです。いやー岩手熱いですね〜!

よろしくお願いします!