【Android】サービス(Service)を使ってバックグラウンド処理をする(1)


おおむねタイトルの通りです。
サービス(Service)と聞いてもピンと来ない感じですが、要はバックグラウンド処理です。
アプリが閉じられても、スリープ状態になってもバックグランドで動き続けます。
常駐アプリなんかを作る時に使えそうですね(^ω^)



AndroidManifest.xmlにServiceを追加


これをしないとうんともすんとも言わなくなるので忘れずに追加です。
applicationタグ内のActivityの後ろあたりに以下のように一行追加します。

        </activity>
         <service android:name="TestService" />
    </application>

</manifest>



名前はこれから追加するサービスの名前を指定します。
今回は「TestService」としました。



Serviceクラスの派生クラスを作成する


クラスファイルを追加してServiceクラスの派生クラスを作成します。
Serversは通常のActivityと似たようなライフサイクルを持ちます。

今回作るサービスでは以下のように状態が遷移していきます。
(Bindを使うと違ったライフサイクルになります)

【Android】サービス(Service)を使ってバックグラウンド処理をする(1):サービス(Service)のライフサイクル

サービス(Service)のライフサイクル



何もしないServiceだと以下のような感じ。


public class TestService extends Service {
  
  @Override
  public void onCreate() {
    Log.i("TestService", "onCreate");
  }
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    Log.i("TestService", "onStartCommand");
    return START_STICKY;
  }

  @Override
  public void onDestroy() {
    Log.i("TestService", "onDestroy");
  }

  @Override
  public IBinder onBind(Intent arg0) {
    Log.i("TestService", "onBind");
    return null;
  }

}




各遷移状態でログを吐くだけです。
自動生成されるonBind関数にも一応入れておきます。


Activityからサービスの開始、終了をする


サービスを使う準備が整いました。
Activityから開始させたり終了させたりする場合は、インテント(Intent)という仕組みを利用します。
画面の遷移などをする時に利用する明示的インテントの方ですね。

サービスを開始する時はstartService関数。
終了させる時はstopService関数を使います。

MainActivityというアクティビティから今回作成したTestServiceを操作する場合は、
以下のように書きます。

// サービスの開始
startService( new Intent( MainActivity.this, TestService.class ) );

// サービスの停止
stopService( new Intent( MainActivity.this, TestService.class ) );



サンプルプログラム;バックグランドでループ処理


開始ボタンを押すとサービス開始、
終了ボタンを押すとサービスが停止だけのサンプルです。

プロジェクトごとはGitHubの方で
ouka-tenshi/Android-Sample/tree/master/ServiceSample

ただ一度動かすだけではバックグラウンド処理っぽくないので、Timerを使って無限ループでログを吐き出し続けるようにします。
(※停止ボタンを押さずにアプリを終了させてしまうと、サービスが動き続けるので注意)

・MainActivity.java
public class MainActivity extends Activity {

  private final int WC = ViewGroup.LayoutParams.WRAP_CONTENT; 

  LinearLayout ll;
  Button btnStart;
  Button btnStop;
    
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.i("MainActivity", "onCreate");
    ll = new LinearLayout(this);
    ll.setGravity( Gravity.CENTER_VERTICAL);
    ll.setOrientation( LinearLayout.VERTICAL );
    
    btnStart = new Button(this);
    btnStop  = new Button(this);
    
    btnStart.setOnClickListener( new ServiceOnClickListener() );
    btnStop.setOnClickListener( new ServiceOnClickListener() );
    btnStart.setText("Service Start");
    btnStop.setText("Service Stop");
    ll.addView( btnStart,  WC );
    ll.addView( btnStop ,  WC );
    setContentView(ll);
  }

  class ServiceOnClickListener implements OnClickListener{

  @Override
  public void onClick(View view) {
    if( view == btnStart ){
      // サービス開始
      startService( new Intent( MainActivity.this, TestService.class ) );
    }else if( view == btnStop ){
      // サービス停止
      stopService( new Intent( MainActivity.this, TestService.class ) );
    }
  }

  }

}




・TestService.java
public class TestService extends Service {
  
  private Timer mTimer = null;
  Handler mHandler = new Handler();

  @Override
  public void onCreate() {
    Log.i("TestService", "onCreate");
  }
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    Log.i("TestService", "onStartCommand");

    // タイマーの設定 1秒毎にループ
    mTimer = new Timer(true);
    mTimer.schedule( new TimerTask(){
      @Override
      public void run(){
        mHandler.post( new Runnable(){
          public void run(){
            Log.d( "TestService" , "Timer run" );
          }
        });
      }
    }, 1000, 1000);

    return START_STICKY;
  }

  @Override
  public void onDestroy() {
    Log.i("TestService", "onDestroy");
    
    // タイマー停止
    if( mTimer != null ){
      mTimer.cancel();
      mTimer = null;
    }
    Toast.makeText(this, "MyService onDestroy", Toast.LENGTH_SHORT).show();
  }

  @Override
  public IBinder onBind(Intent arg0) {
    Log.i("TestService", "onBind");
    return null;
  }

}



ログを確認するとバックグランドで動き続けているのが確認できますね(^ω^)

今回紹介した方式以外にもバインド(bind)を利用した方法があります。
バインドを利用するとサービスに対して開始と停止以外にも色々と操作ができるみたいですね。



関連記事

【Android】サービス(Service)を使ってバックグラウンド処理をする(1)” への1件のコメント

  1. ピンバック: 【Android】サービス(Service)を使ってバックグラウンド処理をする(2) | 桜花満開/テンシホタル