Android
 Computer >> コンピューター >  >> プログラミング >> Android

AndroidでIntentServiceの完了時にアクティビティを更新する方法【LocalBroadcastManager活用】

はじめに:IntentServiceとは

サンプルコードに入る前に、AndroidにおけるIntentServiceについて簡単に確認しておきましょう。IntentServiceは、バックグラウンドで非同期処理を実行するためのサービスクラスです。アクティビティからstartService()を呼び出すと、リクエストごとに新しいインスタンスが生成されることはなく、サービスクラス内の処理が完了すると自動的に停止します。必要に応じて、stopSelf()を使って明示的にサービスを停止させることも可能です。

本記事では、IntentServiceの処理が完了したタイミングでアクティビティ(UI)を更新する方法を、実際のコード例とともに解説します。ポイントはLocalBroadcastManagerを使ったブロードキャスト通信です。

実装手順

ステップ1:プロジェクトの作成

Android Studioを開き、「File」→「New Project」を選択して、必要な情報を入力し、新しいプロジェクトを作成します。

ステップ2:レイアウトファイル(activity_main.xml)の編集

res/layout/activity_main.xml に以下のコードを追加します。

<?xml version = "1.0" encoding = "utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android =   "https://schemas.android.com/apk/res/android"
   xmlns:app = "https://schemas.android.com/apk/res-auto"
   xmlns:tools = "https://schemas.android.com/tools"
   android:layout_width = "match_parent"
   android:layout_height = "match_parent"
   tools:context = ".MainActivity">
   <TextView
      android:id = "@+id/text"
      android:layout_width = "wrap_content"
      android:layout_height = "wrap_content"
      android:text = "Start Service"
      android:textSize = "25sp"
      app:layout_constraintBottom_toBottomOf = "parent"
      app:layout_constraintLeft_toLeftOf = "parent"
      app:layout_constraintRight_toRightOf = "parent"
      app:layout_constraintTop_toTopOf = "parent" />
</android.support.constraint.ConstraintLayout>

このレイアウトでは、画面中央にTextViewを配置しています。ユーザーがIntentServiceからデータを受け取ると、このTextViewの表示内容が更新される仕組みです。

ステップ3:MainActivity.java の実装

src/MainActivity.java に以下のコードを記述します。

package com.example.andy.myapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
    TextView text;
    BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String someValue = intent.getStringExtra("someName");
            text.setText(someValue);
        }
    };
    @Override
    protected void onStart() {
        super.onStart();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.andy.myapplication");
        LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, intentFilter);
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text = findViewById(R.id.text);
        text.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startService(new Intent(MainActivity.this, service.class));
            }
        });
    }
    @Override
    protected void onStop() {
        super.onStop();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
    }
}

ここでのポイントは以下の通りです。

  • BroadcastReceiverを定義し、サービスからのブロードキャストを受信したらTextViewのテキストを更新します。
  • onStart()でレシーバーを登録し、onStop()で解除することで、メモリリークを防止しています。
  • TextViewをタップするとstartService()が呼ばれ、サービスが起動します。

続いて、service.class という新しいクラスを作成し、以下のコードを追加します。

package com.example.andy.myapplication;

import android.app.IntentService;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;

public class service extends IntentService {
    public static volatile boolean shouldStop = false;
    public service() {
        super(service.class.getSimpleName());
    }
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        Intent intent1 = new Intent("com.example.andy.myapplication");
        intent1.putExtra("someName", "Tutorialspoint.com");
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent1);
        if(shouldStop){
            stopSelf();
            return;
        }
    }
}

このサービスクラスでは、onHandleIntent()内で「com.example.andy.myapplication」というアクションを持つインテントを作成し、LocalBroadcastManager経由でブロードキャストを送信しています。これにより、アクティビティ側のレシーバーがデータを受け取り、UIを更新できるのです。また、shouldStopフラグが立っている場合はstopSelf()でサービスを停止します。

ステップ4:マニフェストファイル(manifest.xml)の編集

manifest.xml に以下のコードを追加します。

<?xml version = "1.0" encoding = "utf-8"?>
<manifest xmlns:android = "https://schemas.android.com/apk/res/android"
    package = "com.example.andy.myapplication">
    <uses-permission android:name = "android.permission.WAKE_LOCK"/>
    <application
        android:allowBackup = "true"
        android:icon = "@mipmap/ic_launcher"
        android:label = "@string/app_name"
        android:roundIcon = "@mipmap/ic_launcher_round"
        android:supportsRtl = "true"
        android:theme = "@style/AppTheme">
        <activity android:name = ".MainActivity">
            <intent-filter>
                <action android:name = "android.intent.action.MAIN" />
                <category android:name = "android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name = ".service"/>
    </application>
</manifest>

マニフェストには、作成したサービスクラスを<service>要素として必ず宣言してください。また、バックグラウンド処理中に端末がスリープしないよう、WAKE_LOCKパーミッションも設定しています。

アプリの実行と動作確認

それでは、アプリケーションを実行してみましょう。実機のAndroidスマートフォンをPCに接続していることを前提とします。Android Studioからプロジェクト内のいずれかのアクティビティファイルを開き、ツールバーの「Run」アイコンをクリックします。デバイスを選択して実行すると、まず次のようなデフォルト画面が表示されます。

AndroidでIntentServiceの完了時にアクティビティを更新する方法【LocalBroadcastManager活用】

上記の結果は、アプリ起動時の初期画面です。ここで「Start Service」と表示された部分をタップすると、サービスが起動し、IntentServiceからのブロードキャストを受信したタイミングでTextViewが以下のように更新されます。

AndroidでIntentServiceの完了時にアクティビティを更新する方法【LocalBroadcastManager活用】

まとめ

本記事では、IntentServiceの処理完了時にアクティビティのUIを更新する方法として、LocalBroadcastManagerによるブロードキャスト通信を紹介しました。サービス側でsendBroadcast()を呼び出し、アクティビティ側のBroadcastReceiverで受信してUIに反映させる、という流れが基本パターンです。なお、LocalBroadcastManagerは現在非推奨(Deprecated)となっているため、最新の開発ではLiveDataやFlow、EventBusなどの代替手段を検討するのも良いでしょう。

  1. 【Android】アクティビティで戻るボタンを処理する方法をわかりやすく解説

    本記事では、Androidアプリのアクティビティにおいて戻るボタン(バックキー)を処理する方法を、実際のサンプルコードとともにステップ形式で解説します。手順1:新規プロジェクトを作成するまずはAndroid Studioで新しいプロジェクトを作成しましょう。「File」⇒「New Project」を選択し、必要な項目をすべて入力してプロジェクトのセットアップを完了させてください。手順2:レイアウトファイル(activity_main.xml)を編集するres/layout/activity_main.xml に以下のコードを追加します。中央にテキストとボタンを配置するシンプルなレイアウトです。

  2. 【Android】アクティビティを再起動する方法をサンプルコード付きで解説

    はじめに このチュートリアルでは、Androidアプリでアクティビティ(Activity)を再起動する方法を解説します。アクティビティの再起動は、finish()で現在のアクティビティを終了し、startActivity()で同じインテントを使って再度起動するという手法で実現できます。 ここでは、ボタンをタップするとランダムな数値が表示し直されるサンプルアプリを作成しながら、具体的な手順を紹介します。 ステップ1:新規プロジェクトの作成 Android Studioを開き、「File」→「New Project」を選択して、必要な情報をすべて入力し、新しいプロジェクトを作成します。 ステッ