LoginSignup
5

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-12-06

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

やりたいこと

とてもシンプルで何秒、何分ごとに起動し、
条件をチェックして、条件が満たされている場合処理する、しない場合処理しない感じにします。
例えば、ニュースサイトからバックグラウンドで自動でデータを取得し、バックグラウンドに1時間立っていたら、ニュースを取得し、更新された記事を保存するような感じで使えると思います。
※今回はデータの保存まではやりません。。。

  • Androidでバックグラウンド処理
  • 時間+αな条件での起動
  • ボタンを押したらバックグラウンド処理が停止・再開

こんな感じの作ります

screenshot_2014-12-06-21-31-48_1024.png

ログがこんな感じ

スクリーンショット 2014-12-06 21.10.52.png

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

環境は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を変更するのを前回思いつきましたが、もっと良いやり方があるかと思いますので探してみてください。

完成

ログGif

まとめ

バックグラウンド処理はたまに使用することがあるので、
いままでやったことをまとめることができてよかったです。

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

次は

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5