Android Service - Service 生命周期变化、Service 与 Activity 双向交互

Service 生命周期变化

1、Service
  • BindAndUnbindLifecycleService.java
java 复制代码
public class BindAndUnbindLifecycleService extends Service {

    public static final String TAG = BindAndUnbindLifecycleService.class.getSimpleName();

    private IBinder LocalBinder = new BindAndUnbindLifecycleService.BindAndUnbindLifecycleServiceBinder();

    public class BindAndUnbindLifecycleServiceBinder extends Binder {
        public BindAndUnbindLifecycleService getService() {
            return BindAndUnbindLifecycleService.this;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();

        Log.i(TAG, "onCreate");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind");

        return LocalBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i(TAG, "onUnbind");

        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        Log.i(TAG, "onDestroy");
    }
}
  • AndroidManifest.xml
xml 复制代码
<service android:name=".myservice.BindAndUnbindLifecycleService" />
2、Activity Layout
  1. activity_bind_and_unbind_service_test1.xml
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".BindAndUnbindServiceTest1Activity">

    <Button
        android:id="@+id/btn_bind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="绑定服务"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_unbind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="解绑服务"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_bind" />

    <Button
        android:id="@+id/btn_go"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="跳转"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
  1. activity_bind_and_unbind_service_test2.xml
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".BindAndUnbindServiceTest2Activity">

    <Button
        android:id="@+id/btn_bind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="绑定服务"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_unbind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="解绑服务"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_bind" />

    <Button
        android:id="@+id/btn_back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="回退"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
3、Activity Code
  1. BindAndUnbindServiceTest1Activity.java
java 复制代码
public class BindAndUnbindServiceTest1Activity extends AppCompatActivity {

    public static final String TAG = BindAndUnbindServiceTest1Activity.class.getSimpleName();

    private Button btnBind;
    private Button btnUnbind;
    private Button btnGo;

    private BindAndUnbindLifecycleService bindAndUnbindLifecycleService;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected");

            BindAndUnbindLifecycleService.BindAndUnbindLifecycleServiceBinder bindAndUnbindLifecycleServiceBinder = (BindAndUnbindLifecycleService.BindAndUnbindLifecycleServiceBinder) service;
            BindAndUnbindLifecycleService bindAndUnbindLifecycleService = bindAndUnbindLifecycleServiceBinder.getService();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_bind_and_unbind_service_test1);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        btnBind = findViewById(R.id.btn_bind);
        btnUnbind = findViewById(R.id.btn_unbind);
        btnGo = findViewById(R.id.btn_go);

        btnBind.setOnClickListener(v -> {
            bindService(new Intent(this, BindAndUnbindLifecycleService.class), serviceConnection, Context.BIND_AUTO_CREATE);
        });

        btnUnbind.setOnClickListener(v -> {
            unbindService(serviceConnection);
        });

        btnGo.setOnClickListener(v -> {
            startActivity(new Intent(this, BindAndUnbindServiceTest2Activity.class));
        });
    }
}
  1. BindAndUnbindServiceTest2Activity.java
java 复制代码
public class BindAndUnbindServiceTest2Activity extends AppCompatActivity {

    public static final String TAG = BindAndUnbindServiceTest2Activity.class.getSimpleName();

    private Button btnBind;
    private Button btnUnbind;
    private Button btnBack;

    private BindAndUnbindLifecycleService bindAndUnbindLifecycleService;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected");

            BindAndUnbindLifecycleService.BindAndUnbindLifecycleServiceBinder bindAndUnbindLifecycleServiceBinder = (BindAndUnbindLifecycleService.BindAndUnbindLifecycleServiceBinder) service;
            BindAndUnbindLifecycleService bindAndUnbindLifecycleService = bindAndUnbindLifecycleServiceBinder.getService();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_bind_and_unbind_service_test2);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        btnBind = findViewById(R.id.btn_bind);
        btnUnbind = findViewById(R.id.btn_unbind);
        btnBack = findViewById(R.id.btn_back);

        btnBind.setOnClickListener(v -> {
            bindService(new Intent(this, BindAndUnbindLifecycleService.class), serviceConnection, Context.BIND_AUTO_CREATE);
        });

        btnUnbind.setOnClickListener(v -> {
            unbindService(serviceConnection);
        });

        btnBack.setOnClickListener(v -> {
            finish();
        });
    }
}
4、Test
  1. 在 BindAndUnbindServiceTest1Activity 中,点击【绑定服务】按钮,输出结果

    onCreate
    onBind
    onServiceConnected

  2. 在 BindAndUnbindServiceTest1Activity 中,点击【跳转】按钮,跳转到 BindAndUnbindServiceTest2Activity

  3. 在 BindAndUnbindServiceTest2Activity 中,点击【绑定服务】按钮,输出结果

    onServiceConnected

  4. 在 BindAndUnbindServiceTest2Activity 中,点击【解绑服务】按钮,输出结果

    无内容输出

  5. 在 BindAndUnbindServiceTest2Activity 中,点击【回退】按钮,回退到 BindAndUnbindServiceTest1Activity

  6. 在 BindAndUnbindServiceTest1Activity 中,点击【解绑服务】按钮,输出结果

    onUnbind
    onDestroy


Service 与 Activity 双向交互

1、演示
(1)Service
  • ServiceCallback.java
java 复制代码
public interface ServiceCallback {
    void onTaskComplete(int result);
}
  • CommunicateService.java
java 复制代码
public class CommunicateService extends Service {
    private final IBinder binder = new CommunicateServiceBinder();
    private ServiceCallback serviceCallback;
    private final Handler handler = new Handler(Looper.getMainLooper());

    public class CommunicateServiceBinder extends Binder {
        public CommunicateService getService() {
            return CommunicateService.this;
        }
    }

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

    // 注册回调
    public void setCallback(ServiceCallback serviceCallback) {
        this.serviceCallback = serviceCallback;
    }

    public void startLongTask() {
        new Thread(() -> {

            // 模拟耗时操作
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 发送数据
            int result = 100;
            if (serviceCallback != null) {
                handler.post(() -> serviceCallback.onTaskComplete(result));
            }
        }).start();
    }
}
  • AndroidManifest.xml
xml 复制代码
<service android:name=".myservice.CommunicateService" />
(2)Activity
  • activity_communicate_service_test.xml
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CommunicateServiceTestActivity">

    <TextView
        android:id="@+id/tv_test_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="无"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_execute_task"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="执行任务"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
  • CommunicateServiceTestActivity.java
java 复制代码
public class CommunicateServiceTestActivity extends AppCompatActivity {

    public static final String TAG = CommunicateServiceTestActivity.class.getSimpleName();

    private TextView tvTestContent;

    private CommunicateService communicateService;
    private boolean isBound = false;
    private final ServiceCallback serviceCallback = result -> {
        tvTestContent.setText(String.valueOf(result));
    };
    private final ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected");

            communicateService = ((CommunicateService.CommunicateServiceBinder) service).getService();
            isBound = true;

            communicateService.setCallback(serviceCallback);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected");

            isBound = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_communicate_service_test);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        tvTestContent = findViewById(R.id.tv_test_content);
        findViewById(R.id.btn_execute_task).setOnClickListener(v -> {
            if (communicateService != null) {
                communicateService.startLongTask();
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();

        Intent intent = new Intent(this, CommunicateService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();

        if (isBound) {
            if (communicateService != null) {
                communicateService.setCallback(null);
            }
            unbindService(serviceConnection);
            isBound = false;
        }
    }
}
2、小结
方向 方式 关键代码
Activity → Service 直接调用 Service 方法 communicateService.startLongTask()
Service → Activity 通过回调接口 serviceCallback.onTaskComplete(result)
相关推荐
benbenAItalk12 小时前
数字人口播视频的批量生产实践:素材规范、任务编排与质量验收
java·前端·音视频
sunshine22 girl12 小时前
Java学习二 基本语法2, 算术运算符
java·学习
niucloud-admin12 小时前
JAVA V6 多商户商城 开发文档——插件目录结构
java·开发语言
2601_9628857212 小时前
如何用 Python 扫描 A 股跳空缺口并统计缺口回补概率?
java·前端·python
滕州市燕猫虎计算机科技工作室个体工商户13 小时前
Java锁
java·开发语言
shehuiyuelaiyuehao15 小时前
1计算机是如何工作的
java·计算机网络
一航jason15 小时前
Android平台推理框架及试用场景模型对比
android·人工智能·ai·架构·ai编程·llama
一航jason15 小时前
Android 端侧大模型推理框架对比
android·人工智能·ai·ai编程·llama·ai-native
letisgo515 小时前
JAVA 高级进阶07篇《@Transactional失效的8个场景:代理机制到传播行为》
java·面试·transactional·spring事务·aop动态代理
水域安全老周15 小时前
水趣钓鱼救生衣专利拆解:两级锁紧如何解决落水人衣分离
java·前端·网络