Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีสื่อสารระหว่าง Activity และ Service ใน Android

บทความนี้สาธิตวิธีสื่อสารระหว่าง Activity และ Service แบบพื้นฐาน: เริ่ม/หยุด Service และส่งข้อมูลผ่าน Intent

ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่

Android Studio → File → New Project

ขั้นตอนที่ 2: Layout (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="MainActivity">

    <Button
        android:id="@+id/buttonStart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="74dp"
        android:text="Start Service" />

    <Button
        android:id="@+id/buttonStop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Stop Service" />

</RelativeLayout>

ขั้นตอนที่ 3: MainActivity.java

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    Button buttonStart, buttonStop;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        buttonStart = findViewById(R.id.buttonStart);
        buttonStop = findViewById(R.id.buttonStop);

        buttonStart.setOnClickListener(this);
        buttonStop.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.buttonStart:
                Intent startIntent = new Intent(this, MyService.class);
                // ส่งข้อมูลไป Service
                startIntent.putExtra("message", "Hello from Activity!");
                startService(startIntent);
                break;
            case R.id.buttonStop:
                stopService(new Intent(this, MyService.class));
                break;
        }
    }
}

ขั้นตอนที่ 4: MyService.java

คลิกขวา Package → New → Service → Service ชื่อ MyService:

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.widget.Toast;

public class MyService extends Service {
    MediaPlayer mediaPlayer;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        // สำหรับ Bound Service (ไม่ได้ใช้ในตัวอย่างนี้)
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "Service Created", Toast.LENGTH_LONG).show();
        mediaPlayer = MediaPlayer.create(this, R.raw.song); // ต้องมีไฟล์ res/raw/song.mp3
        mediaPlayer.setLooping(false);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // รับข้อมูลจาก Activity
        if (intent != null) {
            String message = intent.getStringExtra("message");
            Toast.makeText(this, "Service Started: " + message, Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
        }

        mediaPlayer.start();
        return START_STICKY; // รีสตาร์ทถ้าถูก Kill
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
        }
    }
}

ขั้นตอนที่ 5: AndroidManifest.xml

<manifest ...>
    <application ...>
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="false"> <!-- false = ใช้ภายในแอปเท่านั้น -->
        </service>

        <activity android:name=".MainActivity">...</activity>
    </application>
</manifest>

ประเภท Service และการสื่อสาร

ประเภทวิธีสื่อสารUse Case
Started Service (ตัวอย่างนี้)startService/stopService + Intent extrasงานนาน/พื้นหลัง: ดาวน์โหลด, เล่นเพลง
Bound ServicebindService + IBinder Interfaceต้องการโต้ตอบ Real-time, RPC
IntentService (Deprecated)Intent Queue + onHandleIntentงานคิวลำดับ (ใช้ WorkManager แทน)
Foreground ServicestartForeground + Notificationงานที่ผู้ใช้รู้สึก: เพลง, GPS, Download

การสื่อสารขั้นสูง (Bound Service)

// 1. สร้าง Interface
public class MyService extends Service {
    private final IBinder binder = new LocalBinder();

    public class LocalBinder extends Binder {
        MyService getService() { return MyService.this; }
    }

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

    public String getData() { return "Data from Service"; }
}

// 2. ใน Activity
private MyService myService;
private boolean isBound = false;

private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        MyService.LocalBinder binder = (MyService.LocalBinder) service;
        myService = binder.getService();
        isBound = true;
    }
    @Override
    public void onServiceDisconnected(ComponentName name) { isBound = false; }
};

@Override
protected void onStart() {
    super.onStart();
    bindService(new Intent(this, MyService.class), connection, Context.BIND_AUTO_CREATE);
}

@Override
protected void onStop() {
    super.onStop();
    if (isBound) { unbindService(connection); isBound = false; }
}

Modern Approach: WorkManager / Coroutines / Flow

สำหรับงาน Background ปัจจุบันแนะนำ:

  • WorkManager - Deferred, guaranteed background work
  • Kotlin Coroutines + Flow - Async programming
  • Foreground Service + Notification - สำหรับงานที่ User ควรทราบ