【Android】四大组件Service

Service基本概念

Android Service 是一种可以在后台执行长时间运行操作而没有用户界面的应用组件。服务可以由其他应用组件启动(如Activity),一旦启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响。此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信(IPC)。

Service形式

在 Android 中,Service 主要有三种形式,每种形式适用于不同的场景。

1. Started Service(启动式服务)

  • 特点
    • 通过startService()启动,独立运行,与启动组件无直接关联。
    • 需手动调用stopService()stopSelf()终止。
    • 适合执行独立任务(如文件下载、音乐播放)。
  • 生命周期
java 复制代码
onCreate() → onStartCommand() → [运行中] → onDestroy()
  • 关键方法

    • onCreate()

      Service 首次创建时调用(类似 Activity 的 onCreate),用于初始化资源(如线程池、广播接收器)。

    • onStartCommand(Intent intent, int flags, int startId)

      每次调用startService()时触发,传入启动 Intent。返回值决定 Service 被系统终止后的重启策略:

      • START_STICKY :重启 Service,intent为 null(适用于媒体播放)。
      • START_NOT_STICKY:不重启(适用于一次性任务,如文件下载)。
      • START_REDELIVER_INTENT :重启并重新传递最后一个intent
    • onDestroy()

      Service 销毁前调用,需释放资源(如停止线程、注销广播接收器)。

  • 代码示例

java 复制代码
public class MyService extends Service {

    private volatile boolean isRunning = true;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0; i < 10; i++){
                    if(!isRunning){
                        break;
                    }
                    Log.d("MyService", "Service is running: " + i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e){
                        e.printStackTrace();
                    }

                }
                // 打印完成后停止服务
                stopSelf();
            }
        }).start();
        return START_STICKY;
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        isRunning = false;
        Log.d("MyService", "Service is destroyed");
    }
}

2. Bound Service(绑定式服务)

  • 特点

    • 通过bindService()绑定到组件(如 Activity),允许组件与 Service 交互。
    • 多个组件可同时绑定,最后一个组件解绑时 Service 销毁。
    • 适合提供跨组件功能(如获取系统服务、数据共享)。
  • 生命周期

java 复制代码
onCreate() → onBind() → [绑定中] → onUnbind() → onDestroy()
  • 关键方法
    • onBind(Intent intent)
      首次绑定时调用,返回IBinder接口供组件通信。
    • onUnbind(Intent intent)
      最后一个组件解绑时触发,默认返回false。若返回true,下次绑定时会触发onRebind()
    • onRebind(Intent intent)
      onUnbind()返回true后,再次绑定时调用。
  • 代码示例
java 复制代码
public class MyBoundService extends Service {

    private final IBinder binder = new MyLocalBinder();
    private int count = 0;

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


    public class MyLocalBinder extends Binder {
        MyBoundService getService() {
            return MyBoundService.this;
        }
    }

    public void incrementCount() {

        count++;
        Log.d("MyBoundService", "Current count: " + count);
    }

    public int getCount() {
        return count;
    }
}
java 复制代码
public class MainActivity extends AppCompatActivity {
    private MyBoundService myBoundService;
    private boolean isServiceBound = false;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            MyBoundService.MyLocalBinder binder = (MyBoundService.MyLocalBinder) service;
            myBoundService = binder.getService();
            isServiceBound = true;
            // 显示当前计数
            TextView countTextView = findViewById(R.id.count_text_view);
            countTextView.setText("Count: " + myBoundService.getCount());
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isServiceBound = false;
        }
    };

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

        Button incrementButton = findViewById(R.id.increment_button);
        Button unbindButton = findViewById(R.id.unbind_button);
        TextView countTextView = findViewById(R.id.count_text_view);

        incrementButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isServiceBound) {
                    myBoundService.incrementCount();
                    countTextView.setText("Count: " + myBoundService.getCount());
                }
            }
        });

        unbindButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(serviceConnection);
                isServiceBound = false;
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, MyBoundService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

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

3. Foreground Service(前台服务)

  • 特点

    • 执行用户可感知的任务,必须显示通知(如音乐播放器、导航)。
    • 优先级高,系统不易回收,适合持续运行的任务。
  • 启动步骤

    1. 创建通知渠道(Android 8.0+)。
    2. 构建通知并调用startForeground(NOTIFICATION_ID, notification)

4. 混合模式(Started + Bound)

  • 特点

    • 同时支持startService()bindService()
    • 需同时管理两种生命周期,适合既需要独立运行又需要交互的场景。
  • 典型场景

    • 启动服务执行后台任务,同时允许 Activity 绑定获取进度。

5. 总结对比

类型 启动方式 生命周期 通信方式 典型场景
Started Service startService() 独立运行,需手动停止 广播、回调 音乐播放、文件下载
Bound Service bindService() 依赖绑定组件 IBinder接口 数据共享、系统服务代理
Foreground Service startForeground() 高优先级,必须显示通知 同 Started/Bound 导航、实时位置跟踪

IntentService

IntentService 是 Android 提供的一个抽象类 ,继承自 Service,用于简化异步任务处理。它在单独的工作线程中执行任务,并在所有请求处理完成后自动停止,适合处理一次性的后台任务(如网络请求、文件操作)。

  1. 自动创建工作线程 :所有 onHandleIntent() 中的代码在后台线程执行,避免 ANR。
  2. 任务队列处理 :通过 HandlerThreadLooper 实现任务排队,按顺序执行。
  3. 自动停止服务 :所有任务完成后,IntentService 会自动调用 stopSelf()
  4. 简化的生命周期 :只需实现 onHandleIntent(),无需手动管理线程和停止逻辑。

1. 基本用法

创建子类并实现 onHandleIntent()

java 复制代码
public class MyIntentService extends IntentService {

    public MyIntentService() {
        super("MyIntentService"); // 工作线程名称,用于调试
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        // 在后台线程执行耗时任务
        if (intent != null) {
            String action = intent.getAction();
            if ("ACTION_DOWNLOAD".equals(action)) {
                downloadFile(intent.getStringExtra("url"));
            }
        }
    }

    private void downloadFile(String url) {
        // 文件下载逻辑(已在后台线程,无需额外线程)
    }
}

在 Manifest 中注册:

java 复制代码
<service android:name=".MyIntentService" 
    android:enabled="true" 
    android:exported="false"/>

启动服务

java 复制代码
Intent intent = new Intent(this, MyIntentService.class); 
intent.setAction("ACTION_DOWNLOAD"); 
intent.putExtra("url", "https://example.com/file.zip"); 
startService(intent);

2. 核心实现

  1. 工作线程与消息循环
    IntentServiceonCreate() 中创建 HandlerThreadServiceHandler,用于处理任务:

    ini 复制代码
    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
  2. 任务处理流程

    • startService(intent) 触发 onStartCommand(),将 intent 封装为消息发送到工作线程。
    • 工作线程通过 ServiceHandler 接收消息,调用 onHandleIntent() 处理任务。
    • 所有任务完成后,自动调用 stopSelf(msg.arg1) 停止服务。
  3. 任务队列

    多个 intent 会按顺序在工作线程执行,同一时间只处理一个任务。

3. 总结对比

特性 IntentService 普通 Service
线程环境 自动在后台线程执行任务 默认在主线程,需手动创建子线程
任务处理 按顺序处理多个任务 需手动管理多线程并发
自动停止 任务完成后自动停止 需手动调用 stopSelf()stopService()
适用场景 独立、顺序执行的后台任务(如文件下载) 持续运行的服务(如音乐播放)
  1. 不支持并发IntentService 同一时间只处理一个任务,若需并发,可使用 Service + ExecutorService

  2. 无法直接通信:任务执行结果无法直接返回给 Activity,需通过广播或回调。

    java

    ini 复制代码
    // 在 onHandleIntent() 中发送广播
    Intent resultIntent = new Intent("DOWNLOAD_COMPLETED");
    resultIntent.putExtra("result", "success");
    sendBroadcast(resultIntent);
  3. 已过时(Android 8.0+) :推荐使用 WorkManager 替代,支持任务调度、重试和电量优化。

相关推荐
darling_user2 小时前
Android14 耳机按键拍照
android
Mryan20053 小时前
Android 应用多语言与系统语言偏好设置指南
android·java·国际化·android-studio·多语言
刘大浪4 小时前
uniapp 实战新闻页面(一)
android·uni-app
水沝淼燚5 小时前
kmp的实际使用1,开发android项目和native转kotlin开发
android
CYRUS_STUDIO5 小时前
破解 VMP+OLLVM 混淆:通过 Hook jstring 快速定位加密算法入口
android·算法·逆向
没有了遇见5 小时前
Activity 启动模式总结
android
wangjialelele5 小时前
二叉树基本学习
android
雨白9 小时前
Android 音视频播放:MediaPlayer 与 VideoView
android
Harry技术9 小时前
Fragment 和 AppCompatActivity 两个核心组件设计的目的和使用场景对比
android·android studio