一、Service介绍:
在Android中,Service是一种可以在后台运行的组件,它可以执行长时间运行的操作,而不需要与用户交互。Service可以在应用程序的生命周期之外运行,即使用户切换到其他应用程序或锁定屏幕,Service仍然可以继续运行。
Service组件通常用于执行以下任务:
1. 后台播放音乐或音频文件
2. 下载或上传数据
3. 处理网络请求
4. 执行长时间运行的计算任务
Service组件有两种类型:
1. Started Service:这种Service是通过调用startService()方法启动的,它会在后台执行一些操作,直到任务完成或调用stopService()方法停止。Started Service不会自动停止,必须手动停止。
2. Bound Service:这种Service是通过调用bindService()方法启动的,它允许其他组件(如Activity)与Service进行通信。Bound Service会在所有绑定的组件都解绑后自动停止。
Service组件的生命周期包括以下方法:
1. onCreate():在Service创建时调用,用于初始化Service。
2. onStartCommand():在Service启动时调用,用于执行后台任务。
3. onBind():在Service绑定时调用,用于返回一个IBinder对象,以便其他组件可以与Service进行通信。
4. onUnbind():在Service解绑时调用,用于清理资源。
5. onDestroy():在Service销毁时调用,用于释放资源。
需要注意的是,Service运行在主线程中,因此如果执行耗时操作,应该在Service中创建一个新的线程来执行任务,以避免阻塞主线程。
二、服务启动方式
1、调用startService()方法启动服务:
MainActivity:
package com.example.handler;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button startService;
private Button stopService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
startService = findViewById(R.id.bind_service);
stopService = findViewById(R.id.unbind_service);
stopService.setOnClickListener(this);
startService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bind_service:
Intent startIntent = new Intent(this,FirstService.class);
startService(startIntent);
break;
case R.id.unbind_service:
Intent stopIntent = new Intent(this,FirstService.class);
stopService(stopIntent);
break;
}
}
}
activity_main:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/bind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="startService"/>
<Button
android:id="@+id/unbind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="stopService"/>
</LinearLayout>
FirstService:
package com.example.handler;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
public class FirstService extends Service {
private Thread mThread;
private ServiceThread mServiceThread;
private String TAG = "service";
int i =0;
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate: ");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand: ");
mServiceThread = new ServiceThread();
mThread = new Thread(mServiceThread);
mThread.start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
mServiceThread.flag = false;
// 挂起线程
mThread.interrupt();
mThread = null;
Log.i(TAG, "onDestroy: ");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind: ");
return null;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind: ");
return super.onUnbind(intent);
}
private class ServiceThread implements Runnable{
// 用volatile 修饰保证变量在线程间的可见性
volatile boolean flag = true;
@Override
public void run() {
while (flag){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.i(TAG, e.toString());
e.printStackTrace();
}
i++;
Log.i(TAG, "run: 正常运行"+i);
}
}
}
}
运行结果:
2、使用bindService方式启动服务:
MainActivity:
package com.example.handler;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity2 extends AppCompatActivity implements View.OnClickListener{
private Button bindService;
private Button unbindService;
private TextView mTextView,mHandlerText;
private boolean flag = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
initView();
}
private void initView() {
mHandlerText = findViewById(R.id.handler_text);
mTextView = findViewById(R.id.text);
bindService = findViewById(R.id.bind_service);
unbindService = findViewById(R.id.unbind_service);
unbindService.setOnClickListener(this);
bindService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bind_service:
Log.i("MainActivity", "onClick: ");
Intent bindIntent = new Intent(this,SecondService.class);
bindService(bindIntent,mServiceConnection, Context.BIND_AUTO_CREATE);
flag = true;
break;
case R.id.unbind_service:
if (flag){
unbindService(mServiceConnection);
flag = false;
}else {
Toast.makeText(MainActivity2.this,"还没有绑定服务,不能解除绑定",Toast.LENGTH_LONG).show();
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
}
private SecondService.MyBinder binder;
private SecondService mSecondService;
public ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 得到binder对象
binder = (SecondService.MyBinder) service;
// 给Service中message设置一个值
binder.setData("MainActivity:");
// 设置接口回调到获取Service中的数据
mSecondService = binder.getService();
mSecondService.setOnDataCallback(new SecondService.OnDataCallback() {
@Override
public void onDataChange(String msg) {
if (msg.equals("MainActivity:" + 10)){
Bundle bundle = new Bundle();
bundle.putString("name","小明");
Message msg1= mHandler.obtainMessage();
msg1.setData(bundle);
msg1.what = 1;
msg1.arg1 = 26;
mHandler.sendMessage(msg1);
}else if(msg.equals("MainActivity:" + 20)){
mHandler.sendEmptyMessage(2);
}else{
mHandler.post(new Runnable() {
@Override
public void run() {
mTextView.setText(msg);
}
});
}
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
mSecondService = null;
}
};
private Handler mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 1:
String name = (String) msg.getData().get("name");
int age = msg.arg1;
mHandlerText.setText(name+"的年龄为:"+age);
break;
case 2:
Toast.makeText(MainActivity2.this,"发送一个空的Message",Toast.LENGTH_LONG).show();
break;
}
}
};
}
activity_main2:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/bind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="startService"/>
<Button
android:id="@+id/unbind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="stopService"/>
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Handler"
android:gravity="center"
android:textSize="26sp"/>
<TextView
android:id="@+id/handler_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Handler"
android:gravity="center"
android:textSize="26sp"/>
</LinearLayout>
SecondService:
package com.example.handler;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
/**
* 以绑定的方式启动service
*/
public class SecondService extends Service {
private String message;
private boolean isRunning = true;
private IBinder mIBinder = new MyBinder();
private SecondService.ServiceThread mServiceThread;
private Thread mThread;
private String TAG = "SecondService";
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG,"onBind");
mServiceThread = new ServiceThread();
mThread = new Thread(mServiceThread);
mThread.start();
/**
* 返回一个可以在Activity的OnServiceConnected()方法中接收到的binder对象
* 在Activity中通过这个bind对象可以得到Service的实例引用
* 通过获取的Service实例就可以调用相关的方法和属性
*/
return mIBinder;
}
@Override
public void onCreate() {
Log.i(TAG, "onCreate: ");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind: ");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
mServiceThread.flag = false;
Log.i(TAG, "onDestroy: ");
super.onDestroy();
}
public class MyBinder extends Binder{
// 从Activity中传入msg值
public void setData(String msg){
SecondService.this.message = msg;
}
/**
* 返回当前SecondService对象
* 当Activity中获取binder类的实例化
* 可以通过对此方法获取Service类实例
*/
public SecondService getService(){
return SecondService.this;
}
}
private class ServiceThread implements Runnable {
volatile boolean flag = true;
@Override
public void run() {
Log.i(TAG, "run: 线程开始运行------");
int i = 1;
while(flag){
if (mOnDataCallback!=null){
// 通过线程模拟真实场景,循环改变数据
mOnDataCallback.onDataChange(message+i);
i++;
try{
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
private OnDataCallback mOnDataCallback = null;
public void setOnDataCallback(OnDataCallback mOnDataCallback){
this.mOnDataCallback = mOnDataCallback;
}
public interface OnDataCallback{
void onDataChange(String msg);
}
}
运行结果: