The four major components of Android - Detailed Explanation of Service

        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);
        }
    }
};

Guess you like

Origin blog.csdn.net/c19344881x/article/details/129060604