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 Servicelà các thay thế hiện đại