19
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Android Oreoでサービスを使ってみる

Last updated at Posted at 2018-07-16

始めに

Androidではバックグラウンドで処理したい場合serviceを使うことになります。
serviceについて調べて簡単なサンプルコードを作成してみます。

サービスの形式

サービスには2つの形式があり、呼び出すメソッドが異なります。

・開始されたサービス
startService()で開始します。
開始されたサービスは自ら停止させるまで動き続きます。
呼び出し元に結果を戻すことはなく、処理が実行されるのみです。

・バインドされたサービス
bindService()でバインドします。
バインドされたサービスには要求を送信したり、結果を取得したりなど制御が可能です。
ただし、呼び出し元のActivityが終了すると一緒に終了されます。

サービスのコールバックメソッド

onCreate()
 最初に一度呼ばれるので、初期化処理を行います。
onStartCommand()
 サービスで実行する処理を書きます。
onDestroy()
 サービスの終了処理
onBind()
 bindService()で呼び出した場合、呼び出せれます。

Android Oreoでのサービス

バックグラウンド実行制限
Android Oreo(8.0 / API Level 26)からバックグラウンド処理に制限が追加されました。
そのため、上記のstartServiceの代わりに新しく導入されたstartForegroundService()
を使います。
(実際にはSDKのバージョンによって処理を分ける必要があります)

startForegroundService()を使う場合、色々と仕様がありました。
Android Oからのバックグラウンド・サービスの制限事項を実演する。
こちらでユースケースを分かりやすくまとめてくださっていたので、参考にさせていただきました。

ソース

スタートボタンを押してサービス開始、ストップボタンでサービス停止します。
サービス開始10秒後にログ出力するので、その前にアプリをバックグラウンドにしたりして確認してみます。

サービスクラスをManifestに追記

AndroidManifest.xml
<service android:name=".TestService"/>

MainActivity (ボタンの設定のみ)

MainActivity.java
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startButton = findViewById(R.id.button_start);
        Button stopButton = findViewById(R.id.button_stop);

        // サービス開始
        startButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent serviceIntent = new Intent(getApplication(), TestService.class);
                startForegroundService(serviceIntent);
            }
        });

        // サービス停止
        stopButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent serviceIntent = new Intent(getApplication(), TestService.class);
                stopService(serviceIntent);
            }
        });
    }
}

サービスクラス

TestService.java
public class TestService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("DEBUG", "called TestService.onCreate()");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("DEBUG", "called TestService.onStartCommand()");
        String channelId = "service";
        String title = "TestService";

        // 通知設定
        NotificationManager notificationManager =
                (NotificationManager)getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationChannel channel =
                new NotificationChannel(channelId, title, NotificationManager.IMPORTANCE_DEFAULT);

        if(notificationManager != null) {
            notificationManager.createNotificationChannel(channel);
            Notification notification = new Notification.Builder(getApplicationContext(), channelId)
                    .setContentTitle(title)
                    .setSmallIcon(R.drawable.menu)
                    .setContentText("service start")
                    .build();

            // フォアグラウンドで実行
            startForeground(1, notification);

            // 10秒後にログ出力
            try {
                Thread.sleep(10000);
                Log.i("INFO", "processing service");
            } catch (InterruptedException e) {
                e.printStackTrace();

            }
        }

        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("DEBUG", "called TestService.onDestroy()");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

ハマったところ

サービス開始するとクラッシュが繰り返し起こる事象が発生しました。
調べてみたところ、startForeground()で引数に渡す通知の設定が原因でした。
Android8.0だとNotification.setSmallIcon()でAdaptive iconを指定してはいけないらしいです。
私はR.mipmap.ic_launcherを指定してクラッシュしました。
回避のため適当な画像を指定するように修正しています。
Android 8.0 で通知を表示すると System UI がクラッシュする

まとめ

簡単にサービスの動きを検証してみました。(検証方法がちょっとすっきりしませんでしたが、、)
バージョンによって実装方法も異なるうえに、色々と制限も厳しいのでうまく活用するにはもっと勉強が必要そうです。

以下は参考とさせていただいたサイトです。
[Android] Service の使い方
[Android Oreo: 通知とサービスのフォアグラウンド実行]
(https://rakuishi.com/archives/android-oreo-notification-foreground/)
サービス | Android Developers

19
21
0

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
19
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?