Service runs in the background, invisible, and has no interface. The priority is higher than the Activity (kill the Activity first when the memory is insufficient), it runs on the main thread and cannot do time-consuming operations.
1. Service startup method
1、startService()
After being started by startService, the service will run indefinitely. When the stopService() or stopSelf() method is called externally, the service will stop running and be destroyed. When the system resources are insufficient, some unimportant services will be reclaimed, and the service will also stop running and be destroyed after being reclaimed by the system.
life cycle
onCreate()
1. If the service has not been created, the onCreate() callback will be executed after calling startService();
2. If the service is already running, calling startService() will not execute the onCreate() method.
This method is suitable for doing some initialization work.
onStartCommand()
If the startService() method is executed multiple times, the Service's onStartCommand() method will be called multiple times accordingly.
onBind()
The onBind() method in Service is an abstract method, and the Service class itself is an abstract class, so the onBind() method must be rewritten, even if we can't use it.
Use the startService method to start the Service, the onBind() method is basically not used, just return a null when rewriting.
onDestory()
This method of Service will be executed when it is destroyed.
code example
MainActivity.java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 启动service
Intent intent = new Intent(MainActivity.this, TestService.class);
startService(intent);
}
}
TestService.java
public class TestService extends Service {
private static final String TAG = "TestService";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
Log.d(TAG, "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xiaoxu.testdemo">
<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/Theme.MainActivity ">
<service
android:name=".TestService"
android:enabled="true"
android:exported="true" />
<activity
android:name=".MainActivity"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2、bindService
There is a typical client-server model between the service started by bindService and the caller. The caller is the client, and the service is the server. There is only one service, but there can be one or more clients bound to the service. The client mentioned here refers to a component, such as an Activity.
The client can obtain the Service instance through the IBinder interface, so that the client can directly call the method in the Service to achieve flexible interaction, which cannot be realized through the startService method.
bindService The life cycle of the startup service is closely related to the client it is bound to. When the client is destroyed, the client will be automatically unbound from the Service. Of course, the client can also explicitly call the unbindService() method of the Context to unbind the Service. When no client is bound to the Service, the Service will destroy itself.
life cycle
onCreate()
The system calls this method when the service is first created via onStartCommand() and onBind(). This call requires a one-time installation.
onBind()
The system calls this method when other components want to bind the service via bindService(). If you implement this method, you need to return the IBinder object to provide an interface for clients to communicate with the service. You must implement this method, and return null directly if you do not allow binding.
onUnbind()
The system calls this method when a client interrupts a particular interface published by all services.
onRebind()
The system calls this method when a new client connects to the service, and it has previously been notified of disconnection via onUnbind(Intent).
onDestroy()
The system calls this method when the service is no longer useful or is destroyed. Your service needs to implement this method to clean up any resources such as threads, registered listeners, receivers, etc.
code example
MainAcivity.java
public class MainAcivity extends Activity{
private TextService mService = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, TestService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
MyBinder mBinder = (MyBinder)binder;
mService = mBinder.getService();
String name = mService.getUserName();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
MyService.java
public class TestService extends Service{
//通过 binder 实现调用者 client 与 Service 之间的通信
private MyBinder binder = new MyBinder();
// client 可以通过 Binder 获取 Service 实例
public class MyBinder extends Binder {
public MyService getService() {
return TestService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public boolean onUnbind(Intent intent) {
return false;
}
@Override
public void onDestroy() {
super.onDestroy();
}
// getUserName 是 Service 暴露出去供 Client 调用的公共方法
public int getUserName() {
return "XiaoXu";
}
}
3、startForegroundService
The Android 8.0 system does not allow background applications to create background services. You can only use startForegroundService() to start the service. After creating the service, the application must call the service's startForeground() within 5 seconds to display a visible notification, stating that there is a service hanging, otherwise The system will stop the service + ANR prompt.
The system requires Notification to add a Channel, and to execute startForeground() in onStartCommand, because this is mainly for background keep-alive services. If you use startForegroundService() to start the service again during the running of the service, then it will not be called this time. The onCreate method of the service will only call the onStartCommand method. If you don't hang a notification in the onStartCommand method, the system will think that you used startForegroundService but don't give a notification within 5 seconds, and stop the service + ANR prompt stupidly.
code example
MainActivity.java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 启动service
Intent intent = new Intent(this, TestService.class) ;
startForegroundService(intent);
}
}
TestService.java
public class TestService extends Service {
private static final String TAG = "TestService";
private Notification notification;
public static final String CHANNEL_ID_STRING = "service_01";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_STRING,
getString(R.string.app_name),
NotificationManager.IMPORTANCE_LOW);
manager.createNotificationChannel(mChannel);
notification = new Notification.Builder(getApplicationContext(), CHANNEL_ID_STRING).build();
// 下面第一个参数不能为 0
startForeground(1, notification);
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
You can see that using startForegroundService is basically the same as startService, except that the pop-up notification operation is added to the onStartCommand of the Service. The first parameter in the startForeground method cannot be 0, because this notification cannot be the same as the normal notification id, otherwise the notification will be "hidden", which is not what the official wants to see, and Context.startForegroundService() did not then will appear call Service.startForeground() exception.
Two, other
1. Usage scenarios
startService
The foreground application calls startService to start the Service, and the Service runs independently without interacting with the Activity.
bindService
The foreground application calls bindService to start the Service, Android binds to the Service, and the Activity can get an instance of the Service to realize the interaction with the Service.
startForegroundService
The background application calls startForegroundService to start the Service, which is mandatory after Android 8.0 to prompt the user. For example: to start the service when receiving the start-up broadcast, using startService will fail to start, only startForegroundService can be used to start and a notification will pop up to prompt the user.
2. Hide notifications
Sometimes you want to hide resident notifications when starting a service with startForegroundService.
1) Call stopForeground(true) immediately after the notification is displayed to cancel the notification. Tested in Android 11, the service is killed.
2) Register a notification channel with no sound and vibration in advance, and register a notification channel with no sound and vibration. When startForeground uses the same id as the notification, we can hide our notification. (not tried)
Reference: Android8 avoids startForeground method pop-up notification
3. AIDL Service death monitoring
We use the second startup method for the death monitoring of the service.
start service
private void bindService(Context context) {
Intent serviceIntent = new Intent();
serviceIntent.setAction("com.cx.test");
serviceIntent.setPackage("com.cx.test.MyService");
boolean bindSuccess = context.bindService(serviceIntent, mServiceConnection, Service.BIND_AUTO_CREATE);
}
Binding result callback
private IPushInterface mIPushInterface;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
if (iBinder != null) {
//通过AIDL拿到服务
mIPushInterface = IPushInterface.Stub.asInterface(iBinder);
try {
//服务死亡监听
if (mIPushInterface != null) {
mIPushInterface.asBinder().linkToDeath(mDeathRecipient, 0);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
//连接失败
}
};
death listener callback
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (mContext != null) {
//重新绑定服务
bindService(mContext);
}
}
};