In depth exploration of Android Service: the ultimate guide to background services (middle)


introduction


After deeply exploring the basic concept of service and life cycle management, this article will focus on the advanced application of Android Service, including the application of foreground service The problem of implicitly starting the service in Android 5.0 and above, the strategy to ensure the stability of the service, and the efficient use of the service in interprocess communication and complex background task processing. We will show how to apply these advanced features in actual development through actual code examples.


1、 Front desk service and notification

In Android, Foreground Service is a service that users clearly perceive, such as a music player. The foreground service informs the user that the service is in progress by displaying a persistent notification in the status bar. The system tends to keep the foreground service, so that it is not easy to be killed by the system when the memory is insufficient.


The following is a code example of how to create and start a foreground service:

1. Create Notification

First, you need to create a notification, which will be displayed in the status bar to inform the user that the service is running.

 public class MyForegroundService extends Service { private static final int NOTIFICATION_ID = 1; @Override public int onStartCommand(Intent intent,  int flags, int startId) { //Create Notification Notification notification=new NotificationCompat.Builder (this, "channel_id")//A notification channel is required for Android 8.0 and above .setContentTitle("Foreground Service") .setContentText("Service is running in the background") . setSmallIcon (R.drawable.ic_notification)//Status bar icon . setChannelId ("channel_id")//The ID of the notification channel needs to be set for Android 8.0 and above . setOngoing (true)//Notification is persistent .build(); //Start foreground service startForeground(NOTIFICATION_ID,  notification); //Additional logic of the service Return START_STICKY;//or START_REDELIVER_INTENT, selected according to service requirements } @Override public void onDestroy() { //Stop foreground service stopForeground(true); super.onDestroy(); } @Override public IBinder onBind(Intent intent) { //If the service does not need binding, null is returned return null; } }

2. Declare the Service in AndroidManifest.xml


Make sure your AndroidManifest.xml The service has been declared in the file, and if you intend to use the notification channel above Android 8.0 (API level 26), you also need to declare a notification channel in the list.

 <manifest xmlns:android=" http://schemas.android.com/apk/res/android " package="com.example.myapp"> <application ... > <service android:name=".MyForegroundService" /> <!--  Notification channel required for Android version 8.0 or above --> <service android:name=".NotificationChannelService"> <intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter> </service> </application> </manifest>

3. Start foreground service

Finally, in Activity or other components, use Intent to start the foreground service.

 Intent serviceIntent = new Intent(this,  MyForegroundService.class); if (Build. VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent); //  Use startForegroundService for Android 8.0 and above } else { startService(serviceIntent); }

4. Precautions

  • Starting from Android 8.0 (API level 26), all notifications must be sent through notification channels. Make sure you have created at least one notification channel.
  • The notification of the foreground service should be user perceptible to avoid abusing the foreground service.
  • When the service no longer needs to run in the foreground, call stopForeground(true) To stop the foreground state and remove the notification. After that, the service can continue to run as a normal background service.

Through the above steps, you can create and manage foreground services in Android applications.


II Implicit startup problem for Android 5.0 and above

In Android 5.0 (API level 21) and above, it is unsafe to use implicit Intent to start the service, because Google has limited the ability of implicit Intent to start the service in order to improve the security of the system. The following are specific methods and code examples of how to solve the implicit start service problem in Android 5.0 and above.


1. The problem of implicitly starting the service

Before Android 5.0, you can use an implicit Intent to start the service, as shown below:

 Intent serviceIntent = new Intent(); serviceIntent.setAction("com.example.myapp.SERVICE_ACTION"); startService(serviceIntent);

However, in Android 5.0 and above, the above code will throw SecurityException Exception, because the system does not allow the service to be started through implicit Intent.


2. Solution

To solve this problem, you can take one of the following two methods:


Method 1: Set Action and PackageName

Explicitly set Action and PackageName of the current application in Intent, as shown below:

 Intent serviceIntent = new Intent(); serviceIntent.setAction("com.example.myapp.SERVICE_ACTION"); serviceIntent.setPackage(getPackageName()); startService(serviceIntent);

here, getPackageName() Is the package name of the current application, and "com.example.myapp.SERVICE_ACTION" It is the Action string of your service.


Method 2: Convert implicit Intent to explicit Intent

By converting the implicit Intent to the explicit Intent, you can ensure that the Intent starts the service safely. The following is an example code of how to perform the conversion:

 public static Intent getExplicitIntent(Context context,  Intent implicitIntent) { //Retrieve all services matching the given Intent PackageManager pm = context.getPackageManager(); List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0); //Ensure that only one matching service is found if (resolveInfo == null || resolveInfo.size() !=  1) { return null; } //Get component information and create ComponentName ResolveInfo serviceInfo = resolveInfo.get(0); String packageName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceInfo.name; ComponentName component = new ComponentName(packageName,  className); //Create a new Intent, use the old Intent to reuse extras, etc Intent explicitIntent = new Intent(implicitIntent); //Set component to explicit explicitIntent.setComponent(component); return explicitIntent; }

Using the above method, you can start the service as follows:

 Intent mIntent = new Intent(); //  Secondary Intent mIntent.setAction("com.example.myapp.SERVICE_ACTION"); final Intent serviceIntent = new Intent(getExplicitIntent(this,  mIntent)); if (serviceIntent !=  null) { startService(serviceIntent); }

In the above code, we first create an implicit Intent( mIntent ), and then call getExplicitIntent Method to convert it to an explicit Intent( serviceIntent ), and finally use the explicit Intent to safely start the service.


3. Precautions

  • Ensure that the Action string of the service is unique to avoid conflicts with other applications' services.
  • Using explicit Intent instead of implicit Intent can improve the security and stability of applications.
  • Specify the correct permissions for the Service in the manifest file, if necessary.

Through the above methods, you can ensure that the service can be started safely in Android 5.0 and above.


3、 Policy to ensure that the service is not killed

In Android, ensuring that the service will not be killed by the system mainly involves service life cycle management and some specific policies. The following are some common strategies and corresponding code examples.

1. Using START_STICKY Return value

stay onStartCommand Method START_STICKY In this way, when the service is killed by the system due to insufficient memory, the system will try to restart the service.

 @Override public int onStartCommand(Intent intent,  int flags, int startId) { //Process service tasks return START_STICKY; }


2. Using START_REDELIVER_INTENT

return START_REDELIVER_INTENT In this way, when the service is killed, the system will try to retransmit the last Intent to the service.

 @Override public int onStartCommand(Intent intent,  int flags, int startId) { //Process service tasks return START_REDELIVER_INTENT; }

3. Create foreground service

Set the service as the foreground service, which can improve the priority of the service and reduce the risk of being killed by the system.

 @Override public int onStartCommand(Intent intent,  int flags, int startId) { Notification notification = new NotificationCompat.Builder(this, "channel_id") .setContentTitle("Service Title") .setContentText("Service is running") .build(); startForeground(NOTIFICATION_ID,  notification); //Process service tasks return START_STICKY; }

4. Monitor system broadcast restart service

stay onDestroy Method, and then send a custom broadcast in a BroadcastReceiver Monitor the broadcast and restart the service.

 @Override public void onDestroy() { //Send the broadcast to restart the service Intent restartIntent = new Intent(this,  ServiceRestartReceiver.class); sendBroadcast(restartIntent); super.onDestroy(); } public static class ServiceRestartReceiver extends BroadcastReceiver { @Override public void onReceive(Context context,  Intent intent) { //Restart Service context.startService(new Intent(context,  MyService.class)); } }

Ensure that the AndroidManifest.xml Register in ServiceRestartReceiver

 <receiver android:name=".ServiceRestartReceiver" />

5. Monitor service status and restart if necessary

Create an auxiliary service or BroadcastReceiver To monitor the status of your main service and restart it when it is killed.

 public class ServiceWatcher extends BroadcastReceiver { @Override public void onReceive(Context context,  Intent intent) { if (isServiceRunning(context,  MyService.class)) { // Service is running,  no action needed } else { // Service is not running,  restart it context.startService(new Intent(context,  MyService.class)); } } public boolean isServiceRunning(Context context,  Class<?> serviceClass) { ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); for (ActivityManager. RunningServiceInfo service : manager.getRunningServices(Integer. MAX_VALUE)) { if (serviceClass.getName().equals(service.service.getClassName())) { return true; } } return false; } }

And on AndroidManifest.xml Register in ServiceWatcher

 <receiver android:name=".ServiceWatcher" />

When using these strategies, you need to consider the user experience of the application and the rational use of system resources. Abuse of these mechanisms may lead to a shortage of system resources, affect the overall performance of the device, or even cause applications to be killed by the system or users. Therefore, use these strategies wisely and only when necessary.


4、 Effective inter process communication (IPC) through service

In Android, Service can realize inter process communication (IPC), allowing different applications or different components of the same application to exchange information. IPC is usually implemented through Binder mechanism. The following are the steps and code examples of interprocess communication through Service.


1. Define Binder class

First, you need to define a Binder class, which is the communication bridge between the Service and the client.

 public class MyBinder extends Binder { public MyService getService() { return MyService.this; } } public class MyService extends Service { private final IBinder binder = new MyBinder(); // ... }

2. Implement the onBind method

In Service, override onBind Method and returns the Binder object.

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

3. Binding Service on Client

Client use bindService Method binds to Service.

 private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name,  IBinder service) { //Get the instance of the service MyBinder myBinder = (MyBinder) service; MyService myService = myBinder.getService(); //Now you can call the public method of Service } @Override public void onServiceDisconnected(ComponentName name) { //Handling Service Disconnection } }; Intent serviceIntent = new Intent(this,  MyService.class); bindService(serviceIntent,  serviceConnection, Context.BIND_AUTO_CREATE);

4. Define public methods in Service

In Service, define the public methods that clients can call.

 public class MyService extends Service { // ... public void doSomething() { //Perform some operations } }

The client calls these methods through Binder:

 myService.doSomething();

5. Handling cross process communication

If the service needs cross process communication, you can use Messenger Or AIDL (Android interface definition language).


(1) , using Messenger

Step 1: create a Handler And a Messenger

 public class MyMessengerService extends Service { private final Messenger messenger = new Messenger(new IncomingHandler()); @Override public IBinder onBind(Intent intent) { return messenger.getBinder(); } private class IncomingHandler extends Handler { public void handleMessage(Message msg) { //Processing messages //You can choose to reply to messages Message replyMsg = Message.obtain(); //Set reply message and send try { messenger.send(replyMsg); } catch (RemoteException e) { e.printStackTrace(); } } } }

The second step is to send messages to the service on the client side.

 private ServiceConnection serviceConnection = new ServiceConnection() { // ... }; Intent serviceIntent = new Intent(this,  MyMessengerService.class); bindService(serviceIntent,  serviceConnection, Context.BIND_AUTO_CREATE); //Send message Message message = Message.obtain(); message.what = SOME_MSG; //You can set more information, such as arg1, Arg2, obj, etc messenger.send(message);

(2) Using AIDL

The first step is to define the AIDL interface.

 // ISomeService.aidl package com.example.myapp; interface ISomeService { void doSomething(); }

The second step is to implement the AIDL interface.

 public class SomeService extends Service { private final ISomeService.Stub binder = new ISomeService.Stub() { @Override public void doSomething() { //Implementation method } }; @Override public IBinder onBind(Intent intent) { return binder; } }

Step 3: The client binds the Service and calls the method.

 private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name,  IBinder service) { ISomeService someService = ISomeService.Stub.asInterface(service); //Calling remote methods try { someService.doSomething(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { // ... } }; Intent serviceIntent = new Intent(this,  SomeService.class); bindService(serviceIntent,  serviceConnection, Context.BIND_AUTO_CREATE);

With these methods, you can realize the interprocess communication of the Service. Remember when AndroidManifest.xml Declare the Service in the and add it for the cross process communication service android:exported="true" Property.


5、 Practical case: use Service to realize complex background task processing

In Android, using the Service to perform the file download task is a common application scenario. The following is an example of using the Service to download files, including the creation and binding of the Service, as well as starting the download task on the client and receiving the download progress update.


1. Create Download Service

First, create a Service class to handle the download task.

 public class DownloadService extends Service { public static final String ACTION_DOWNLOAD = "com.example. DOWNLOAD"; public static final String EXTRA_URL = "com.example. EXTRA_URL"; private DownloadManager downloadManager; private Handler handler; @Override public void onCreate() { super.onCreate(); downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); handler = new Handler(); } @Override public int onStartCommand(Intent intent,  int flags, int startId) { String downloadUrl = intent.getStringExtra(EXTRA_URL); if (downloadUrl !=  null && !downloadUrl.isEmpty()) { startDownload(downloadUrl); } return START_NOT_STICKY; } private void startDownload(String url) { //Create Download Request DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); request.setNotificationVisibility(DownloadManager. Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); request.setTitle("Downloading..."); request.setDescription("Downloading file..."); request.setDestinationInExternalFilesDir(this, "Download", "example.apk"); //Add the download request to the download queue downloadManager.enqueue(request); } @Nullable @Override public IBinder onBind(Intent intent) { Return null;//If binding is not required, null is returned } }

2. Declare the Service in AndroidManifest.xml

Applied AndroidManifest.xml Service is declared in the file.

 <manifest xmlns:android=" http://schemas.android.com/apk/res/android " package="com.example.myapp"> <application ... > <service android:name=".DownloadService" /> </application> </manifest>

3. Start Download Service

In other components of the application, such as Activity, use startService Method to start the download service.

 Intent downloadIntent = new Intent(this,  DownloadService.class); downloadIntent.setAction(DownloadService. ACTION_DOWNLOAD); downloadIntent.putExtra(DownloadService. EXTRA_URL,  " http://example.com/file.apk "); startService(downloadIntent);

4. Receive download progress

In order to receive the download progress, a broadcast receiver can be used.

Send progress update broadcast in Service:

 private BroadcastReceiver downloadReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context,  Intent intent) { if (DownloadManager. ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) { long downloadId = intent.getLongExtra(DownloadManager. EXTRA_DOWNLOAD_ID, -1); //Check whether the download is successful boolean success = queryDownloadStatus(downloadId); if (success) { //The download is successful. You can install files or perform other operations here } } } }; private boolean queryDownloadStatus(long downloadId) { DownloadManager.Query query = new DownloadManager.Query(); Cursor cursor = downloadManager.query(query); boolean success = false; if (cursor.moveToFirst()) { int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)); success = DownloadManager.STATUS_SUCCESSFUL == status; } cursor.close(); return success; } @Override public void onDestroy() { //Log off radio receiver unregisterReceiver(downloadReceiver); super.onDestroy(); } //Register the broadcast receiver in the startDownload method Intent filter = new Intent(DownloadManager. ACTION_DOWNLOAD_COMPLETE); filter.setPackage(getPackageName()); registerReceiver(downloadReceiver,  new IntentFilter(filter));

stay AndroidManifest.xml Add a dynamic permission for the downloaded broadcast in:

 <manifest ... > <uses-permission android:name="com.android.providers.downloads.permission.DOWNLOAD_COMPLETED"/> ... </manifest>

Please note that starting from Android 8.0 (API level 26) DownloadManager The system will automatically verify and scan the downloaded files. Ensure that your application complies with the relevant authority and code of conduct.

In this way, you can use the Service to implement the file download task and receive a notification after the download is completed. This method can ensure that the download task runs independently in the background, even if the user switches to other applications or locks the screen.


6、 Conclusion

As one of the cornerstones of Android platform, Service provides developers with broad application space with its powerful background processing capability and flexible inter process communication mechanism. However, The stability and efficiency of services are still challenges for developers. In the future technology exploration, we will further discuss the best practices of Service, including how to optimize the performance of Service, and how to achieve more efficient system level operations through Service. Please look forward to our next in-depth analysis article to take you into the efficient development world of service.


  • twelve
    give the thumbs-up
  • step on
  • fifteen
    Collection
    Think it's good? One click collection
  •  Reward
    Reward
  • one
    comment
This article mainly discusses the service The challenge and optimization of garbage collection on the. Relative to x86 architecture service Device, ARM service There are big differences in memory consistency and processor instructions. Therefore, when garbage collection is carried out, special optimization should be carried out for these differences. Here is the article in Key contents of Firstly, this paper introduces the working principle of garbage collection algorithm based on pointer, and points out that in ARM service Some of the challenges of garbage collection. his in Memory consistency is an important issue. In ARM architecture in The consistency of memory access needs to be managed by software, which will increase the cost of garbage collection. At the same time, the difference of processor instructions will also affect the efficiency of garbage collection. Secondly, this paper introduces some optimization measures. For example, the exception handling mechanism is used to reduce the dependence on memory consistency, the large page is used to increase the efficiency of memory access, and the signaling mechanism is used to avoid using the ARM architecture in TLB failure, etc. In addition, the parallel garbage collection algorithm on multi-core processors and the use of hardware assisted technology to improve the efficiency of garbage collection are also discussed. Finally, this paper summarizes ARM service Challenges and optimization of garbage collection on the Internet. ARM service Garbage collection on the processor needs to comprehensively consider memory consistency, processor instructions, multi-core processors and other issues, and optimize for specific scenarios. In the future, with ARM service The application scope of the device has gradually expanded, The garbage collection optimization of ARM architecture will also become more important.

Is "relevant recommendation" helpful to you?

  • Very unhelpful
  • No help
  • commonly
  • to be helpful to
  • Very helpful
Submit
Comments one
Add Red Packet

Please fill in the red envelope greeting or title

individual

The minimum number of red packets is 10

element

The minimum amount of red packet is 5 yuan

Current balance three point four three element Go to recharge>
To be paid: ten element
Achieve 100 million technicians!
After receiving, you will automatically become a fan of the blogger and the red envelope owner rule
hope_wisdom
Red packet sent

Reward the author

W rain or shine w

Your encouragement will be the greatest impetus for my creation

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
Scan code for payment: ¥1
Obtaining
Scan code for payment

Your balance is insufficient, please change the scanning code to pay or Recharge

Reward the author

Paid in element
Payment with balance
Click to retrieve
Scan code for payment
Wallet balance zero

Deduction description:

1. The balance is the virtual currency of wallet recharge, and the payment amount is deducted at a ratio of 1:1.
2. The balance cannot be directly purchased and downloaded, but VIP, paid columns and courses can be purchased.

Balance recharge