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

AndroidのIntentServiceからUIを継続的に更新する方法

IntentServiceとは

AndroidのIntentServiceは、バックグラウンド処理を非同期(ワーカースレッド)で実行するためのサービスコンポーネントです。ActivityなどからstartService()を呼び出しても、リクエストごとに新しいインスタンスが生成されることはなく、onHandleIntent()内の処理が完了するとサービスは自動的に停止します。必要に応じてstopSelf()を呼び出し、手動で停止させることも可能です。

本記事では、IntentServiceから送信されたデータを受け取り、UIを継続的に更新する方法をサンプルコードとともに解説します。

実装手順

ステップ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を1つ配置しています。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.os.Handler;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import java.util.Timer;
import java.util.TimerTask;

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);
        final Handler handler = new Handler();
        TimerTask timertask = new TimerTask() {
            @Override
            public void run() {
                handler.post(new Runnable() {
                    public void run() {
                        startService(new Intent(MainActivity.this, service.class));
                    }
                });
            }
        };
        Timer timer = new Timer();
        timer.schedule(timertask, 0, 10000);
    }

    @Override
    protected void onStop() {
        super.onStop();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
    }
}

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

  • BroadcastReceiver:サービスから送信されたブロードキャストを受信し、TextViewのテキストを更新します。
  • LocalBroadcastManager:アプリ内部だけで完結するブロードキャストを送受信できる仕組みです。他アプリに漏れないため安全です。
  • Timer+Handler:10秒ごとにメインスレッド上でサービスを起動します。
  • onStart()/onStop():画面の表示・非表示に合わせてレシーバーの登録と解除を行い、メモリリークを防ぎます。

ステップ4:service.java(IntentService)の作成

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

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");
        for(int i = 0; i < 10; i++) {
            intent1.putExtra("someName", "Tutorialspoint.com "+i);
            LocalBroadcastManager.getInstance(this).sendBroadcast(intent1);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if(shouldStop) {
            stopSelf();
            return;
        }
    }
}

onHandleIntent()内では、1秒間隔で10回ループ処理を行い、そのたびにカウント値をExtraに格納してブロードキャストを送信しています。これにより、Activity側のTextViewがリアルタイムに更新されていきます。

ステップ5: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>

サービスをマニフェストに宣言することで、システムがサービスコンポーネントを認識できるようになります。

アプリの実行と結果確認

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

AndroidのIntentServiceからUIを継続的に更新する方法

AndroidのIntentServiceからUIを継続的に更新する方法

実行結果を見ると、IntentServiceから送信されたデータによって、UIが継続的に更新されていることが確認できます。

補足:最新のAndroid開発における注意点

なお、本記事で使用しているandroid.supportライブラリやIntentService自体は、現在では非推奨(Deprecated)となっています。最新のプロジェクトでは、AndroidXへの移行に加え、バックグラウンド処理にはWorkManagerKotlin Coroutines(コルーチン)の利用が推奨されています。ただし、「サービス側の処理結果をブロードキャストで受け取り、UIに反映する」という本記事の基本的な設計思想は、現代の実装でもそのまま活かせる考え方です。

  1. Androidアプリで端末起動時にサービスを自動開始する方法【コード例付きで解説】

    はじめにAndroidアプリの中には、端末が再起動された後もバックグラウンド処理を継続したいケースがあります。本記事では、BroadcastReceiverとBOOT_COMPLETEDアクションを組み合わせて、端末の起動完了時にサービスを自動的に開始する方法を、実際のコード例とともにステップごとに解説します。この仕組みを実現するには、まずシステムから「起動完了」のブロードキャストを受け取るレシーバーを用意し、その中でActivityやServiceを起動します。以下の手順に従って実装していきましょう。Step 1:新規プロジェクトを作成するAndroid Studioを開き、「File」→「

  2. Androidからマルウェアを削除する方法|感染の兆候と予防策を徹底解説

    現代社会において、スマートフォンは生活に欠かせない存在となっています。銀行アプリ、ナビゲーションアプリ、各種ユーティリティアプリなど、個人の重要な情報や機能がほぼすべて詰まっています。だからこそ、プライバシーを守るためにも、スマートフォンをしっかりと保護することが何よりも重要です。パソコンと同様に、Androidスマートフォンもウイルス、トロイの木馬、スパイウェア、アドウェアなどの悪意あるプログラム(マルウェア)に感染する可能性があります。Androidマルウェアの主な目的は、機密情報の窃取、無関係な広告の表示によるユーザーの誤誘導、悪質なサイトへのリダイレクトなどです。マルウェアはさまざまな