introduction
1、 Front desk service and notification
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; } }
<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>
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); }
-
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.
II Implicit startup problem for Android 5.0 and above
Intent serviceIntent = new Intent(); serviceIntent.setAction("com.example.myapp.SERVICE_ACTION"); startService(serviceIntent);
Intent serviceIntent = new Intent(); serviceIntent.setAction("com.example.myapp.SERVICE_ACTION"); serviceIntent.setPackage(getPackageName()); startService(serviceIntent);
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; }
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); }
-
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.
3、 Policy to ensure that the service is not killed
@Override public int onStartCommand(Intent intent, int flags, int startId) { //Process service tasks return START_STICKY; }
@Override public int onStartCommand(Intent intent, int flags, int startId) { //Process service tasks return START_REDELIVER_INTENT; }
@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; }
@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)); } }
<receiver android:name=".ServiceRestartReceiver" />
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; } }
<receiver android:name=".ServiceWatcher" />
4、 Effective inter process communication (IPC) through service
public class MyBinder extends Binder { public MyService getService() { return MyService.this; } } public class MyService extends Service { private final IBinder binder = new MyBinder(); // ... }
@Override public IBinder onBind(Intent intent) { return binder; }
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);
public class MyService extends Service { // ... public void doSomething() { //Perform some operations } }
myService.doSomething();
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(); } } } }
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);
// ISomeService.aidl package com.example.myapp; interface ISomeService { void doSomething(); }
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; } }
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);
5、 Practical case: use Service to realize complex background task processing
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 } }
<manifest xmlns:android=" http://schemas.android.com/apk/res/android " package="com.example.myapp"> <application ... > <service android:name=".DownloadService" /> </application> </manifest>
Intent downloadIntent = new Intent(this, DownloadService.class); downloadIntent.setAction(DownloadService. ACTION_DOWNLOAD); downloadIntent.putExtra(DownloadService. EXTRA_URL, " http://example.com/file.apk "); startService(downloadIntent);
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));
<manifest ... > <uses-permission android:name="com.android.providers.downloads.permission.DOWNLOAD_COMPLETED"/> ... </manifest>
6、 Conclusion