Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Truyền thông giữa Activity và Service trong Android

Truyền thông giữa Activity và Service trong Android

Hướng dẫn này minh họa cách giao tiếp giữa Activity và Service (Started Service) cơ bản: Start/Stop service, Service phát nhạc nền.

Bước 1: Tạo dự án mới

Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.

Bước 2: Thiết kế giao diện (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_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Stop Service" />
</RelativeLayout>

Bước 3: Code 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
    public 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);
    }
    
    public void onClick(View src) {
        switch (src.getId()) {
            case R.id.buttonStart:
                startService(new Intent(this, MyService.class));
                break;
            case R.id.buttonStop:
                stopService(new Intent(this, MyService.class));
                break;
        }
    }
}

Bước 4: Tạo Service (MyService.java)

Chuột phải package → New → Service → Service (IntentService) hoặc tạo class thủ công:

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 myPlayer;
    
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null; // Started service, không binding
    }
    
    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "Service Created", Toast.LENGTH_LONG).show();
        
        // Chuẩn bị MediaPlayer với file raw/song.mp3
        myPlayer = MediaPlayer.create(this, R.raw.song);
        myPlayer.setLooping(false); // Không lặp lại
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
        myPlayer.start();
        return START_STICKY; // Khởi động lại nếu bị kill
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
        if (myPlayer != null) {
            myPlayer.stop();
            myPlayer.release();
        }
    }
}

Bước 5: Thêm file audio

Tạo thư mục res/raw/ (New → Android Resource Directory → raw) và đặt file song.mp3 vào đó.

Bước 6: Cấu hình AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android" package="app.com.sample">
    <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">
        
        <!-- Khai báo Service -->
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true">
        </service>
        
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Chạy ứng dụng

Kết nối thiết bị, chạy app. Nhấn "Start Service" → nhạc phát, Toast "Service Started". Nhấn "Stop Service" → nhạc dừng, Toast "Service Stopped". Đóng app, nhạc vẫn phát (service chạy nền).

Vòng đời Service (Started Service):
onCreate() → onStartCommand() → [Running] → onDestroy()

- onCreate(): Chạy 1 lần khi service tạo lần đầu
- onStartCommand(): Chạy mỗi lần startService() gọi
- onDestroy(): Chạy khi stopService() hoặc hệ thống kill

Các loại Service và giao tiếp nâng cao

1. Bound Service (Giao tiếp 2 chiều qua IBinder)

// Service
public class BoundService extends Service {
    private final IBinder binder = new LocalBinder();
    
    public class LocalBinder extends Binder {
        BoundService getService() { return BoundService.this; }
    }
    
    @Override
    public IBinder onBind(Intent intent) { return binder; }
    
    public String getData() { return "Data from service"; }
}

// Activity
private BoundService boundService;
private boolean isBound = false;

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

bindService(new Intent(this, BoundService.class), connection, Context.BIND_AUTO_CREATE);
// Gọi: boundService.getData();
unbindService(connection);

2. Messenger/IPC (Giao tiếp cross-process)

// Service
Messenger messenger = new Messenger(new Handler() {
    @Override
    public void handleMessage(Message msg) {
        // Xử lý message từ client
        Message reply = Message.obtain(null, REPLY_CODE);
        reply.obj = "Response from service";
        try { msg.replyTo.send(reply); } catch (RemoteException e) {}
    }
});

@Override
public IBinder onBind(Intent intent) { return messenger.getBinder(); }

// Client
Messenger serviceMessenger = new Messenger(serviceBinder);
Message msg = Message.obtain(null, REQUEST_CODE);
msg.replyTo = new Messenger(new Handler() {
    @Override
    public void handleMessage(Message msg) { /* Xử lý reply */ }
});
serviceMessenger.send(msg);

3. Foreground Service (Android 8.0+ bắt buộc)

// Trong onCreate()
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("Music Player")
    .setContentText("Playing: " + songName)
    .setSmallIcon(R.drawable.ic_music)
    .build();
startForeground(NOTIFICATION_ID, notification);
Lưu ý Android 8.0+ (API 26):
  • Background Service bị giới hạn: không thể chạy lâu nếu app không ở foreground
  • Phải dùng startForeground() với Notification cho long-running service
  • JobScheduler, WorkManager, Foreground Service là các thay thế hiện đại