全部笔记All notes

Android Service服务组件完全指南

阅读 8m 27s8m 27s read

系列导航

概述

Service是Android四大组件之一,用于在后台执行长时间运行的操作,没有用户界面。Service可以在应用被销毁后继续运行,适合执行不需要和用户交互且需要长期运行的任务,如网络请求、文件下载、音乐播放等。

学习目标

  • 理解Service的生命周期和使用场景
  • 掌握Started Service和Bound Service的区别
  • 学习前台服务的实现方法
  • 了解现代化的后台任务解决方案
  • 掌握Service的进程间通信
  • 实现完整的音乐播放器服务

Service基础

什么是Service?

Service是在后台运行的组件,有以下特点:

  • 无界面:Service没有用户界面
  • 长时间运行:可以在后台长时间执行任务
  • 独立生命周期:即使启动它的组件被销毁,Service仍可继续运行
  • 主线程运行:Service默认运行在主线程,需要手动创建线程处理耗时操作

创建Service

// Java实现
public class MyService extends Service {
    private static final String TAG = "MyService";
    
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "Service onCreate");
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "Service onStartCommand");
        
        // 在这里执行后台任务
        performBackgroundTask();
        
        // 返回值决定服务被杀死后的重启行为
        return START_STICKY;
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "Service onBind");
        return null; // 不提供绑定功能时返回null
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "Service onDestroy");
    }
    
    private void performBackgroundTask() {
        // 耗时操作应该在新线程中执行
        new Thread(() -> {
            // 执行后台任务
            Log.d(TAG, "Performing background task");
        }).start();
    }
}
// Kotlin实现
class MyService : Service() {
    companion object {
        private const val TAG = "MyService"
    }
    
    override fun onCreate() {
        super.onCreate()
        Log.d(TAG, "Service onCreate")
    }
    
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.d(TAG, "Service onStartCommand")
        
        // 在这里执行后台任务
        performBackgroundTask()
        
        // 返回值决定服务被杀死后的重启行为
        return START_STICKY
    }
    
    override fun onBind(intent: Intent): IBinder? {
        Log.d(TAG, "Service onBind")
        return null // 不提供绑定功能时返回null
    }
    
    override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, "Service onDestroy")
    }
    
    private fun performBackgroundTask() {
        // 耗时操作应该在新线程中执行
        Thread {
            // 执行后台任务
            Log.d(TAG, "Performing background task")
        }.start()
    }
}

在清单文件中注册

<manifest ...>
    <application ...>
        <service 
            android:name=".MyService"
            android:enabled="true"
            android:exported="false"
            android:description="@string/service_description">
            <!-- 可以添加intent-filter来响应隐式Intent -->
            <intent-filter>
                <action android:name="com.example.action.MY_SERVICE" />
            </intent-filter>
        </service>
    </application>
</manifest>

服务的生命周期

生命周期方法

Service有两种运行模式,对应不同的生命周期:

Started Service生命周期

onCreate() → onStartCommand() → Service Running → onDestroy()

Bound Service生命周期

onCreate() → onBind() → Service Running → onUnbind() → onDestroy()

生命周期方法详解

public class ServiceLifecycle extends Service {
    
    @Override
    public void onCreate() {
        super.onCreate();
        // 服务第一次创建时调用
        // 执行一次性的初始化操作
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 每次通过startService()启动服务时调用
        // 在这里处理业务逻辑
        
        // 返回值说明:
        // START_NOT_STICKY: 服务被杀死后不会重建
        // START_STICKY: 服务被杀死后会重建,但intent为null
        // START_REDELIVER_INTENT: 服务被杀死后会重建,并重新传递最后的intent
        return START_STICKY;
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        // 客户端通过bindService()绑定服务时调用
        // 返回IBinder接口用于通信
        return binder;
    }
    
    @Override
    public boolean onUnbind(Intent intent) {
        // 所有客户端都解绑时调用
        // 返回true表示希望在下次绑定时调用onRebind()
        return super.onUnbind(intent);
    }
    
    @Override
    public void onRebind(Intent intent) {
        // 当onUnbind()返回true后,有新客户端绑定时调用
        super.onRebind(intent);
    }
    
    @Override
    public void onDestroy() {
        // 服务被销毁前调用
        // 清理资源
        super.onDestroy();
    }
}

启动服务(Started Service)

基本用法

// Java实现 - 启动和停止服务
public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    
    // 启动服务
    public void startService(View view) {
        Intent serviceIntent = new Intent(this, MyService.class);
        serviceIntent.putExtra("data", "Hello Service");
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // Android 8.0+ 需要使用startForegroundService
            startForegroundService(serviceIntent);
        } else {
            startService(serviceIntent);
        }
    }
    
    // 停止服务
    public void stopService(View view) {
        Intent serviceIntent = new Intent(this, MyService.class);
        stopService(serviceIntent);
    }
}

处理服务重启

public class RobustService extends Service {
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 处理空intent的情况(服务重启时可能发生)
        if (intent != null) {
            String action = intent.getAction();
            if ("ACTION_DOWNLOAD".equals(action)) {
                String url = intent.getStringExtra("url");
                startDownload(url);
            }
        }
        
        // 根据需求选择合适的返回值
        return START_REDELIVER_INTENT; // 确保重启后能重新接收Intent
    }
    
    private void startDownload(String url) {
        // 在后台线程中执行下载
        new Thread(() -> {
            try {
                // 模拟下载过程
                downloadFile(url);
                
                // 下载完成后停止服务
                stopSelf();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }
}

绑定服务(Bound Service)

创建可绑定的服务

// Java实现
public class BoundService extends Service {
    private final IBinder binder = new LocalBinder();
    private final Random random = new Random();
    
    // 用于客户端绑定的Binder类
    public class LocalBinder extends Binder {
        BoundService getService() {
            return BoundService.this;
        }
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
    
    // 服务提供的公共方法
    public int getRandomNumber() {
        return random.nextInt(100);
    }
    
    public void performTask(String task) {
        Log.d("BoundService", "Performing task: " + task);
    }
}

绑定到服务

// Java实现 - 在Activity中绑定服务
public class BindingActivity extends AppCompatActivity {
    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;
            
            // 现在可以调用服务的方法了
            int randomNumber = boundService.getRandomNumber();
            Log.d("BindingActivity", "Random number: " + randomNumber);
        }
        
        @Override
        public void onServiceDisconnected(ComponentName name) {
            // 服务意外断开连接时调用
            isBound = false;
        }
    };
    
    @Override
    protected void onStart() {
        super.onStart();
        // 绑定服务
        Intent intent = new Intent(this, BoundService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        // 解绑服务
        if (isBound) {
            unbindService(connection);
            isBound = false;
        }
    }
    
    // 使用服务
    public void useService(View view) {
        if (isBound && boundService != null) {
            boundService.performTask("Important Task");
            int number = boundService.getRandomNumber();
            Toast.makeText(this, "Random: " + number, Toast.LENGTH_SHORT).show();
        }
    }
}

使用Messenger进行IPC通信

// Service端实现
public class MessengerService extends Service {
    static final int MSG_SAY_HELLO = 1;
    
    // 处理客户端消息的Handler
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "Hello!", 
                        Toast.LENGTH_SHORT).show();
                    
                    // 回复客户端
                    try {
                        Message reply = Message.obtain(null, MSG_SAY_HELLO);
                        msg.replyTo.send(reply);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
    
    final Messenger messenger = new Messenger(new IncomingHandler());
    
    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }
}

前台服务(Foreground Service)

创建前台服务

从Android 8.0开始,后台服务受到严格限制,需要使用前台服务来执行长时间运行的任务。

// Java实现
public class ForegroundService extends Service {
    private static final String CHANNEL_ID = "ForegroundServiceChannel";
    private static final int NOTIFICATION_ID = 1;
    
    @Override
    public void onCreate() {
        super.onCreate();
        createNotificationChannel();
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 创建通知
        Notification notification = createNotification();
        
        // 启动前台服务
        startForeground(NOTIFICATION_ID, notification);
        
        // 在后台线程执行任务
        doBackgroundWork();
        
        return START_NOT_STICKY;
    }
    
    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                CHANNEL_ID,
                "前台服务通道",
                NotificationManager.IMPORTANCE_DEFAULT
            );
            channel.setDescription("用于前台服务的通知通道");
            
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
    }
    
    private Notification createNotification() {
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
            0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
        
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("前台服务运行中")
            .setContentText("正在执行后台任务...")
            .setSmallIcon(R.drawable.ic_notification)
            .setContentIntent(pendingIntent)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT);
        
        // 添加操作按钮
        Intent stopIntent = new Intent(this, ForegroundService.class);
        stopIntent.setAction("STOP_SERVICE");
        PendingIntent stopPendingIntent = PendingIntent.getService(this,
            0, stopIntent, PendingIntent.FLAG_IMMUTABLE);
        builder.addAction(R.drawable.ic_stop, "停止", stopPendingIntent);
        
        return builder.build();
    }
    
    private void doBackgroundWork() {
        new Thread(() -> {
            // 执行长时间运行的任务
            for (int i = 0; i < 100; i++) {
                Log.d("ForegroundService", "Working... " + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 任务完成后停止服务
            stopForeground(true);
            stopSelf();
        }).start();
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

请求权限和启动前台服务

<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- Android 13+ 需要POST_NOTIFICATIONS权限 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<service 
    android:name=".ForegroundService"
    android:foregroundServiceType="dataSync" />
// 启动前台服务
public void startForegroundService(View view) {
    Intent serviceIntent = new Intent(this, ForegroundService.class);
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(serviceIntent);
    } else {
        startService(serviceIntent);
    }
}

IntentService

IntentService是Service的子类,用于处理异步请求。它在单独的工作线程中处理所有请求,处理完成后自动停止。

⚠️ 注意:IntentService在API 30中已被废弃,推荐使用JobIntentService或WorkManager。

// Java实现
public class MyIntentService extends IntentService {
    private static final String TAG = "MyIntentService";
    
    public MyIntentService() {
        super("MyIntentService");
    }
    
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        // 这个方法在工作线程中执行
        if (intent != null) {
            String action = intent.getAction();
            if ("ACTION_DOWNLOAD".equals(action)) {
                String url = intent.getStringExtra("url");
                downloadFile(url);
            } else if ("ACTION_UPLOAD".equals(action)) {
                String filePath = intent.getStringExtra("file_path");
                uploadFile(filePath);
            }
        }
    }
    
    private void downloadFile(String url) {
        Log.d(TAG, "Downloading from: " + url);
        // 模拟下载
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        Log.d(TAG, "Download complete");
    }
    
    private void uploadFile(String filePath) {
        Log.d(TAG, "Uploading file: " + filePath);
        // 模拟上传
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        Log.d(TAG, "Upload complete");
    }
}

JobScheduler和WorkManager

JobScheduler(API 21+)

// 创建JobService
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class MyJobService extends JobService {
    private static final String TAG = "MyJobService";
    
    @Override
    public boolean onStartJob(JobParameters params) {
        Log.d(TAG, "Job started");
        
        // 在后台线程执行任务
        new Thread(() -> {
            doBackgroundWork();
            // 任务完成,通知系统
            jobFinished(params, false);
        }).start();
        
        // 返回true表示任务还在执行
        return true;
    }
    
    @Override
    public boolean onStopJob(JobParameters params) {
        Log.d(TAG, "Job stopped");
        // 返回true表示希望重新调度这个任务
        return true;
    }
    
    private void doBackgroundWork() {
        // 执行后台任务
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

// 调度任务
public void scheduleJob(Context context) {
    JobScheduler jobScheduler = (JobScheduler) 
        context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
    
    JobInfo jobInfo = new JobInfo.Builder(1, 
            new ComponentName(context, MyJobService.class))
        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
        .setRequiresCharging(true)
        .setPeriodic(15 * 60 * 1000) // 15分钟
        .build();
    
    jobScheduler.schedule(jobInfo);
}

WorkManager(推荐)

// Kotlin实现
class UploadWorker(
    context: Context,
    params: WorkerParameters
) : Worker(context, params) {
    
    override fun doWork(): Result {
        // 获取输入数据
        val imageUri = inputData.getString("IMAGE_URI") ?: return Result.failure()
        
        try {
            // 执行上传操作
            uploadImage(imageUri)
            
            // 返回成功,可以传递输出数据
            val outputData = Data.Builder()
                .putString("UPLOAD_URL", "https://example.com/image.jpg")
                .build()
            
            return Result.success(outputData)
        } catch (e: Exception) {
            // 失败后可以重试
            return Result.retry()
        }
    }
    
    private fun uploadImage(uri: String) {
        // 实际的上传逻辑
        Thread.sleep(3000) // 模拟上传
    }
}

// 使用WorkManager
class MainActivity : AppCompatActivity() {
    
    fun scheduleUpload(imageUri: Uri) {
        val uploadData = Data.Builder()
            .putString("IMAGE_URI", imageUri.toString())
            .build()
        
        val constraints = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .setRequiresBatteryNotLow(true)
            .build()
        
        val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
            .setInputData(uploadData)
            .setConstraints(constraints)
            .addTag("upload")
            .build()
        
        WorkManager.getInstance(this).enqueue(uploadRequest)
        
        // 观察工作状态
        WorkManager.getInstance(this)
            .getWorkInfoByIdLiveData(uploadRequest.id)
            .observe(this) { workInfo ->
                when (workInfo?.state) {
                    WorkInfo.State.SUCCEEDED -> {
                        val uploadUrl = workInfo.outputData.getString("UPLOAD_URL")
                        Toast.makeText(this, "上传成功: $uploadUrl", 
                            Toast.LENGTH_SHORT).show()
                    }
                    WorkInfo.State.FAILED -> {
                        Toast.makeText(this, "上传失败", Toast.LENGTH_SHORT).show()
                    }
                    else -> {
                        // 其他状态
                    }
                }
            }
    }
}

服务间通信

使用AIDL进行进程间通信

// IRemoteService.aidl
interface IRemoteService {
    int getPid();
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
    String getMessage();
}
// 服务端实现
public class RemoteService extends Service {
    
    private final IRemoteService.Stub binder = new IRemoteService.Stub() {
        @Override
        public int getPid() throws RemoteException {
            return Process.myPid();
        }
        
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean,
                float aFloat, double aDouble, String aString) throws RemoteException {
            // 处理基本类型
        }
        
        @Override
        public String getMessage() throws RemoteException {
            return "Hello from Remote Service!";
        }
    };
    
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}

音乐播放器实战

完整的音乐播放服务

// Java实现
public class MusicService extends Service {
    private static final String TAG = "MusicService";
    private MediaPlayer mediaPlayer;
    private final IBinder binder = new MusicBinder();
    private boolean isPrepared = false;
    
    // 用于Activity绑定的Binder
    public class MusicBinder extends Binder {
        public MusicService getService() {
            return MusicService.this;
        }
    }
    
    @Override
    public void onCreate() {
        super.onCreate();
        initMediaPlayer();
    }
    
    private void initMediaPlayer() {
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        
        // 设置监听器
        mediaPlayer.setOnPreparedListener(mp -> {
            isPrepared = true;
            notifyMusicPrepared();
        });
        
        mediaPlayer.setOnCompletionListener(mp -> {
            notifyMusicCompleted();
        });
        
        mediaPlayer.setOnErrorListener((mp, what, extra) -> {
            Log.e(TAG, "MediaPlayer error: " + what + ", " + extra);
            return false;
        });
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
    
    // 播放音乐
    public void playMusic(String path) {
        try {
            mediaPlayer.reset();
            mediaPlayer.setDataSource(path);
            mediaPlayer.prepareAsync(); // 异步准备
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    // 播放/暂停
    public void playOrPause() {
        if (isPrepared) {
            if (mediaPlayer.isPlaying()) {
                mediaPlayer.pause();
            } else {
                mediaPlayer.start();
                startProgressUpdate();
            }
        }
    }
    
    // 停止播放
    public void stop() {
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            isPrepared = false;
        }
    }
    
    // 跳转到指定位置
    public void seekTo(int position) {
        if (isPrepared) {
            mediaPlayer.seekTo(position);
        }
    }
    
    // 获取当前播放位置
    public int getCurrentPosition() {
        return isPrepared ? mediaPlayer.getCurrentPosition() : 0;
    }
    
    // 获取音乐总时长
    public int getDuration() {
        return isPrepared ? mediaPlayer.getDuration() : 0;
    }
    
    // 是否正在播放
    public boolean isPlaying() {
        return mediaPlayer != null && mediaPlayer.isPlaying();
    }
    
    // 进度更新
    private final Handler progressHandler = new Handler();
    private final Runnable progressRunnable = new Runnable() {
        @Override
        public void run() {
            if (mediaPlayer != null && mediaPlayer.isPlaying()) {
                notifyProgressUpdate(getCurrentPosition(), getDuration());
                progressHandler.postDelayed(this, 1000);
            }
        }
    };
    
    private void startProgressUpdate() {
        progressHandler.post(progressRunnable);
    }
    
    // 回调接口
    public interface MusicServiceListener {
        void onMusicPrepared();
        void onProgressUpdate(int currentPosition, int duration);
        void onMusicCompleted();
    }
    
    private MusicServiceListener listener;
    
    public void setMusicServiceListener(MusicServiceListener listener) {
        this.listener = listener;
    }
    
    private void notifyMusicPrepared() {
        if (listener != null) {
            listener.onMusicPrepared();
        }
    }
    
    private void notifyProgressUpdate(int currentPosition, int duration) {
        if (listener != null) {
            listener.onProgressUpdate(currentPosition, duration);
        }
    }
    
    private void notifyMusicCompleted() {
        if (listener != null) {
            listener.onMusicCompleted();
        }
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        progressHandler.removeCallbacks(progressRunnable);
        if (mediaPlayer != null) {
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }
}

音乐播放器Activity

public class MusicPlayerActivity extends AppCompatActivity 
        implements MusicService.MusicServiceListener {
    
    private MusicService musicService;
    private boolean isBound = false;
    private SeekBar seekBar;
    private TextView tvCurrentTime, tvTotalTime;
    private ImageButton btnPlayPause;
    private ObjectAnimator rotateAnimator;
    
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            MusicService.MusicBinder binder = (MusicService.MusicBinder) service;
            musicService = binder.getService();
            musicService.setMusicServiceListener(MusicPlayerActivity.this);
            isBound = true;
            
            // 加载音乐
            loadMusic();
        }
        
        @Override
        public void onServiceDisconnected(ComponentName name) {
            isBound = false;
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_music_player);
        
        initViews();
        setupAnimator();
    }
    
    private void initViews() {
        seekBar = findViewById(R.id.seekBar);
        tvCurrentTime = findViewById(R.id.tvCurrentTime);
        tvTotalTime = findViewById(R.id.tvTotalTime);
        btnPlayPause = findViewById(R.id.btnPlayPause);
        
        // SeekBar监听
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser && isBound) {
                    musicService.seekTo(progress);
                }
            }
            
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {}
            
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {}
        });
        
        // 播放/暂停按钮
        btnPlayPause.setOnClickListener(v -> {
            if (isBound) {
                musicService.playOrPause();
                updatePlayPauseButton();
            }
        });
    }
    
    private void setupAnimator() {
        ImageView albumCover = findViewById(R.id.albumCover);
        rotateAnimator = ObjectAnimator.ofFloat(albumCover, "rotation", 0f, 360f);
        rotateAnimator.setDuration(10000);
        rotateAnimator.setRepeatCount(ObjectAnimator.INFINITE);
        rotateAnimator.setInterpolator(new LinearInterpolator());
    }
    
    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, MusicService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        if (isBound) {
            unbindService(connection);
            isBound = false;
        }
    }
    
    private void loadMusic() {
        // 从raw资源加载音乐
        String path = "android.resource://" + getPackageName() + "/" + R.raw.sample_music;
        musicService.playMusic(path);
    }
    
    @Override
    public void onMusicPrepared() {
        runOnUiThread(() -> {
            int duration = musicService.getDuration();
            seekBar.setMax(duration);
            tvTotalTime.setText(formatTime(duration));
            btnPlayPause.setEnabled(true);
        });
    }
    
    @Override
    public void onProgressUpdate(int currentPosition, int duration) {
        runOnUiThread(() -> {
            seekBar.setProgress(currentPosition);
            tvCurrentTime.setText(formatTime(currentPosition));
            
            if (musicService.isPlaying() && !rotateAnimator.isRunning()) {
                rotateAnimator.start();
            }
        });
    }
    
    @Override
    public void onMusicCompleted() {
        runOnUiThread(() -> {
            seekBar.setProgress(0);
            tvCurrentTime.setText("00:00");
            updatePlayPauseButton();
            rotateAnimator.pause();
        });
    }
    
    private void updatePlayPauseButton() {
        if (musicService != null && musicService.isPlaying()) {
            btnPlayPause.setImageResource(R.drawable.ic_pause);
            if (!rotateAnimator.isRunning()) {
                rotateAnimator.resume();
            }
        } else {
            btnPlayPause.setImageResource(R.drawable.ic_play);
            rotateAnimator.pause();
        }
    }
    
    private String formatTime(int milliseconds) {
        int seconds = milliseconds / 1000;
        int minutes = seconds / 60;
        seconds = seconds % 60;
        return String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
    }
}

性能优化

1. 避免在主线程执行耗时操作

public class OptimizedService extends Service {
    private HandlerThread handlerThread;
    private Handler backgroundHandler;
    
    @Override
    public void onCreate() {
        super.onCreate();
        
        // 创建后台线程
        handlerThread = new HandlerThread("ServiceBackgroundThread");
        handlerThread.start();
        backgroundHandler = new Handler(handlerThread.getLooper());
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 在后台线程执行任务
        backgroundHandler.post(() -> {
            performLongRunningTask();
            
            // 任务完成后停止服务
            stopSelf(startId);
        });
        
        return START_NOT_STICKY;
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        handlerThread.quitSafely();
    }
}

2. 使用JobScheduler或WorkManager

// 使用WorkManager处理周期性任务
class PeriodicSyncWorker(
    context: Context,
    params: WorkerParameters
) : Worker(context, params) {
    
    override fun doWork(): Result {
        // 执行同步任务
        return try {
            syncData()
            Result.success()
        } catch (e: Exception) {
            if (runAttemptCount < 3) {
                Result.retry()
            } else {
                Result.failure()
            }
        }
    }
    
    private fun syncData() {
        // 同步数据的具体实现
    }
}

// 调度周期性任务
fun schedulePeriodicSync(context: Context) {
    val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .setRequiresBatteryNotLow(true)
        .build()
    
    val syncRequest = PeriodicWorkRequestBuilder<PeriodicSyncWorker>(
        15, TimeUnit.MINUTES
    ).setConstraints(constraints)
        .build()
    
    WorkManager.getInstance(context).enqueueUniquePeriodicWork(
        "periodic_sync",
        ExistingPeriodicWorkPolicy.REPLACE,
        syncRequest
    )
}

3. 合理使用WakeLock

public class WakeLockService extends Service {
    private PowerManager.WakeLock wakeLock;
    
    @Override
    public void onCreate() {
        super.onCreate();
        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(
            PowerManager.PARTIAL_WAKE_LOCK,
            "MyApp::MyWakeLockTag"
        );
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 获取WakeLock
        wakeLock.acquire(10*60*1000L /*10 minutes*/);
        
        // 执行需要保持CPU唤醒的任务
        new Thread(() -> {
            try {
                performCriticalTask();
            } finally {
                // 确保释放WakeLock
                if (wakeLock.isHeld()) {
                    wakeLock.release();
                }
                stopSelf();
            }
        }).start();
        
        return START_NOT_STICKY;
    }
}

最佳实践

1. 选择合适的服务类型

场景推荐方案
短时间后台任务Service + 线程
长时间后台任务前台服务
定期执行任务WorkManager
需要精确时间控制AlarmManager + Service
与UI紧密交互Bound Service
简单异步任务AsyncTask/协程

2. 服务生命周期管理

public class LifecycleAwareService extends Service {
    private final CompositeDisposable disposables = new CompositeDisposable();
    
    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化资源
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 确保服务不会无限期运行
        scheduleStopSelf();
        return START_NOT_STICKY;
    }
    
    private void scheduleStopSelf() {
        disposables.add(
            Observable.timer(30, TimeUnit.MINUTES)
                .subscribe(aLong -> stopSelf())
        );
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        // 清理资源
        disposables.clear();
    }
}

3. 错误处理和恢复

public class ResilientService extends Service {
    private static final int MAX_RETRIES = 3;
    private int retryCount = 0;
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        try {
            performTask();
            retryCount = 0; // 重置重试计数
        } catch (Exception e) {
            Log.e("ResilientService", "Task failed", e);
            
            if (retryCount < MAX_RETRIES) {
                retryCount++;
                // 延迟重试
                scheduleRetry(intent, startId);
                return START_REDELIVER_INTENT;
            } else {
                // 达到最大重试次数,停止服务
                stopSelf(startId);
            }
        }
        
        return START_NOT_STICKY;
    }
    
    private void scheduleRetry(Intent intent, int startId) {
        new Handler().postDelayed(() -> {
            onStartCommand(intent, 0, startId);
        }, 5000 * retryCount); // 指数退避
    }
}

调试技巧

1. 使用ADB命令调试服务

# 查看运行中的服务
adb shell dumpsys activity services

# 查看特定应用的服务
adb shell dumpsys activity services com.example.app

# 强制停止服务
adb shell am stopservice com.example.app/.MyService

# 启动服务
adb shell am startservice com.example.app/.MyService

2. 服务状态日志

public class DebuggableService extends Service {
    private static final String TAG = "DebuggableService";
    
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate - Thread: " + Thread.currentThread().getName());
        dumpServiceState("onCreate");
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand - startId: " + startId);
        dumpServiceState("onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }
    
    private void dumpServiceState(String method) {
        if (BuildConfig.DEBUG) {
            Log.d(TAG, String.format(
                "[%s] Process: %d, Thread: %s, Memory: %d MB",
                method,
                android.os.Process.myPid(),
                Thread.currentThread().getName(),
                Runtime.getRuntime().totalMemory() / (1024 * 1024)
            ));
        }
    }
}

3. 使用StrictMode检测问题

public class StrictModeService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        
        if (BuildConfig.DEBUG) {
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectAll()
                .penaltyLog()
                .build());
        }
    }
}

常见问题

1. Service vs IntentService vs JobIntentService

问题:应该使用哪种服务?

解答:

  • Service:需要手动管理线程,适合复杂的后台任务
  • IntentService:自动在工作线程执行,任务完成后自动停止(已废弃)
  • JobIntentService:兼容JobScheduler和旧版本的Service(已废弃)
  • 推荐:使用WorkManager处理后台任务

2. 服务被系统杀死

问题:服务经常被系统杀死

解决方案:

// 1. 使用前台服务
startForeground(NOTIFICATION_ID, notification);

// 2. 返回START_STICKY或START_REDELIVER_INTENT
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return START_STICKY; // 服务被杀死后会重启
}

// 3. 在单独的进程中运行
// AndroidManifest.xml
<service
    android:name=".MyService"
    android:process=":remote" />

3. 内存泄漏

问题:Service持有Activity引用导致内存泄漏

解决方案:

// 使用WeakReference
public class SafeService extends Service {
    private WeakReference<Activity> activityRef;
    
    public void setActivity(Activity activity) {
        activityRef = new WeakReference<>(activity);
    }
    
    private void updateUI() {
        Activity activity = activityRef.get();
        if (activity != null && !activity.isFinishing()) {
            // 安全地更新UI
        }
    }
}

4. ANR问题

问题:Service导致ANR

解决方案:

// 始终在后台线程执行耗时操作
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    // 不要在这里执行耗时操作
    new Thread(() -> {
        // 在这里执行耗时操作
        performLongRunningTask();
    }).start();
    
    return START_STICKY;
}

相关文章

总结

Service是Android中执行后台任务的重要组件,但使用时需要注意:

  1. 选择合适的服务类型:根据任务特点选择Service、前台服务或WorkManager
  2. 避免阻塞主线程:Service默认运行在主线程,耗时操作必须在子线程执行
  3. 管理服务生命周期:合理启动和停止服务,避免资源浪费
  4. 处理系统限制:了解不同Android版本的后台执行限制
  5. 考虑电池优化:使用JobScheduler或WorkManager实现电池友好的后台任务
  6. 正确处理进程间通信:使用AIDL、Messenger或其他IPC机制

通过合理使用Service,可以实现强大的后台功能,提升应用的用户体验。