Android application process keep-alive solution in practice

  1. Foreground service: Set the service running the application as a foreground service to let the user know that the application is running in the background, and the system will give it a certain priority to reduce the probability of being killed by the system. However, it should be noted that using the foreground service to keep alive cannot occupy a large amount of the user's notification bar, otherwise the user may feel annoyed and uninstall the application.

  2. JobScheduler: A method of scheduling tasks introduced in Android 5.0, which can flexibly arrange the task execution time of the application and improve the efficiency and stability of task execution.

  3. AlarmManager: It can start the service or broadcast of the application regularly in the background to ensure that the application will not be killed by the system in the background. But at the same time, we also need to pay attention to avoid excessive use of AlarmManager and reduce the power consumption and resource occupation of applications in the background.

  4. Dual-process guarding: By opening two processes, the application runs two different processes in the system to protect each other, ensuring that once one process is destroyed by the system, the other process will wake up the application again. However, the dual-process daemon will cause high memory usage of the application, and some mobile phone manufacturers may disable this function.

  5. Keep-alive framework: There are some third-party keep-alive frameworks on the market, which can maintain the activity of the application through some technical means, such as CPU usage, wake-up lock, etc. However, it should be noted that these frameworks may cause additional resource consumption and power consumption.

The above are the main solutions for keeping alive the Android application process. Of course, the keep-alive policies of different applications may vary due to application characteristics and development needs.

1. Front desk service

1. Add permissions to access network status and foreground services in the AndroidManifest.xml file:

复制<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

2. Create a background service, let Service inherit the Service class, implement its onBind() method and onStartCommand() method, keep the service running in the foreground, and start it again when the service is destroyed:

复制public class MyService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Notification notification = new NotificationCompat.Builder(this, "CHANNEL_ID")
                .setContentTitle("App is running in background")
                .setContentText("Tap to open")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(PendingIntent.getActivity(this, 0, intent, 0))
                .build();

        startForeground(1, notification);

        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        Toast.makeText(this, "Service destroyed", Toast.LENGTH_SHORT).show();

        Intent intent = new Intent(getApplicationContext(), MyService.class);
        startService(intent);
    }
}

3. Start the service in the MainActivity class:

复制public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(getApplicationContext(), MyService.class);
        startService(intent);
    }
}

A PendingIntent is used in the notification bar in the foreground service to start MainActivity, so that the user can open the application when clicking the notification bar. When the service is destroyed, the service is restarted by starting another Intent object, thus realizing the keep-alive function. It should be noted that the service will continue to run after the program exits, and the service needs to be stopped by calling the stopService() method or the stopForeground() method, otherwise it may continue to run in the background and increase the system burden.

Two, dual process guardian

  • 1. Create a daemon service class DaemonService:

    复制public class DaemonService extends Service {
        private final static String TAG = DaemonService.class.getSimpleName();
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            Log.i(TAG, "onCreate: DaemonService created.");
        }
    
        @Override
        public void onTaskRemoved(Intent rootIntent) {
            super.onTaskRemoved(rootIntent);
    
            Log.i(TAG, "onTaskRemoved: App is killed.");
    
            // 在应用被杀死前,启动 ProtectService 来尝试拉活
            Intent intent = new Intent(getApplicationContext(), ProtectService.class);
            startService(intent);
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
    

    2. Create a live service class ProtectService:

    复制public class ProtectService extends Service {
        private final static String TAG = ProtectService.class.getSimpleName();
        private final static int NOTIFY_ID = 1;
        private final static String CHANNEL_NAME = "keep_alive";
        private final static String CHANNEL_DESCRIPTION = "keep_alive";
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            Log.i(TAG, "onCreate: ProtectService created.");
    
            startForeground(NOTIFY_ID, getNotification());
    
            startService(new Intent(getApplicationContext(), DaemonService.class));
        }
    
        private Notification getNotification() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
                NotificationChannel channel = new NotificationChannel(CHANNEL_NAME, CHANNEL_DESCRIPTION, NotificationManager.IMPORTANCE_HIGH);
                notificationManager.createNotificationChannel(channel);
    
                Notification.Builder builder = new Notification.Builder(this, CHANNEL_NAME);
                builder.setSmallIcon(R.mipmap.ic_launcher);
                builder.setContentTitle(getString(R.string.app_name));
                builder.setContentText(getString(R.string.text_keep_alive));
    
                return builder.build();
            } else {
                NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
                builder.setSmallIcon(R.mipmap.ic_launcher);
                builder.setContentTitle(getString(R.string.app_name));
                builder.setContentText(getString(R.string.text_keep_alive));
    
                return builder.build();
            }
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
    

    3. Start the guardian service and pull service in MainActivity:

    复制public class MainActivity extends AppCompatActivity {
        private final static String TAG = MainActivity.class.getSimpleName();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Log.i(TAG, "onCreate: MainActivity created.");
    
            startService(new Intent(getApplicationContext(), DaemonService.class));
            startService(new Intent(getApplicationContext(), ProtectService.class));
        }
    }
    

    If the application is killed by the system, capture it in real time, and try to call ProtectService to wake up the application, let it run in the foreground again, and ensure that it is rarely killed in the background. At the same time, since the foreground service is turned on, switching between the foreground and the background frequently may result in a large number of "resident notifications" in the user's notification bar, which needs to be paid attention to.

  • Add the function of starting the mobile phone to the above functions
  • Ok, the following is a complete code example for adding the mobile phone startup function based on the above solution:

    1. Create a BroadcastReceiver class to monitor the mobile phone's boot broadcast, and create an Intent object to start the guardian service and pull the service:

    复制public class BootReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
                Intent service = new Intent(context, DaemonService.class);
                context.startService(service);
    
                Intent protect = new Intent(context, ProtectService.class);
                context.startService(protect);
            }
        }
    }
    

    2. Register permissions and BroadcastReceiver in the AndroidManifest.xml file:

    复制<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    
    <receiver
        android:name=".BootReceiver"
        android:enabled="true"
        android:exported="true"
        android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    

    3. In the MainActivity class, check whether the daemon service and the live service are running, and if not, start them manually:

    复制public class MainActivity extends AppCompatActivity {
        private final static String TAG = MainActivity.class.getSimpleName();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Log.i(TAG, "onCreate: MainActivity created.");
    
            if (!isServiceRunning(this, DaemonService.class.getName())) {
                startService(new Intent(getApplicationContext(), DaemonService.class));
            }
    
            if (!isServiceRunning(this, ProtectService.class.getName())) {
                startService(new Intent(getApplicationContext(), ProtectService.class));
            }
        }
    
        private boolean isServiceRunning(Context context, String serviceName) {
            ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
            List<ActivityManager.RunningServiceInfo> list = am.getRunningServices(Integer.MAX_VALUE);
    
            for (ActivityManager.RunningServiceInfo info : list) {
                if (serviceName.equals(info.service.getClassName())) {
                    return true;
                }
            }
    
            return false;
        }
    }
    

    The above is a complete code example for adding the mobile phone startup function, which can automatically start the service after the device is restarted, and keep the running state of the application in the background.

三、Job Scheduler

1. Create a JobService class and implement its onStartJob() and onStopJob() methods:

复制public class MyJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
        Log.i(TAG, "onStartJob");

        // 在此添加需要执行的任务
        // ...

        jobFinished(params, false);

        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        return true;
    }
}

2. Register the JobService and necessary permissions in the AndroidManifest.xml file:

复制<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<application>
    ...

    <service
        android:name=".MyJobService"
        android:permission="android.permission.BIND_JOB_SERVICE" />

    ...
</application>

3. Invoke the corresponding JobScheduler when the application starts to realize keep-alive:

复制public class MainActivity extends AppCompatActivity {
    private static final int JOB_ID = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);

        JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, new ComponentName(getPackageName(), MyJobService.class.getName()));
        builder.setPeriodic(10000);
        builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);

        if (scheduler.schedule(builder.build()) <= 0) {
            Log.e(TAG, "onCreate: JobScheduler failed.");
        }
    }
}

Here we set the keep-alive time to 10 seconds, and set the network request to not distinguish between Wifi or mobile network. After the application is recycled, the JobScheduler will restart the application and invoke the onStartJob() method of the MyJobService class, and add tasks to be executed in this method to complete the keep-alive of the application.

It should be noted that JobScheduler is not 100% guaranteed to be able to execute tasks accurately according to the set time. The system may delay the execution time of tasks for some reasons, and different versions of Android may have different levels of support.

If the task requires immediate execution, you can use the startService() method or ForegroundService to implement it, and use it in conjunction with JobScheduler to ensure that it will not be killed in the background.

4. Alarm Manager

1. Create a resident process Service and implement its onBind(), onStartCommand() and onDestroy() methods:

复制public class KeepAliveService extends Service {
    private static final int NOTIFY_ID = 1001;
    private static final String CHANNEL_ID = "MY_CHANNEL_ID";
    private static final String CHANNEL_NAME = "MY_CHANNEL_NAME";

    private PendingIntent pendingIntent;

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");

        Intent notificationIntent = new Intent(this, MainActivity.class);
        pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

        Notification notification = null;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);

            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            manager.createNotificationChannel(channel);

            notification = new Notification.Builder(this, CHANNEL_ID)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText(getString(R.string.text_keep_alive))
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(false)
                    .setCategory(NotificationCompat.CATEGORY_SERVICE)
                    .build();
        } else {
            notification = new NotificationCompat.Builder(this)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText(getString(R.string.text_keep_alive))
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(false)
                    .setPriority(NotificationCompat.PRIORITY_MIN)
                    .setCategory(NotificationCompat.CATEGORY_SERVICE)
                    .build();
        }

        startForeground(NOTIFY_ID, notification);

        // 定时发送广播
        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent alarmIntent = new Intent(getApplicationContext(), KeepAliveReceiver.class);
        pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmIntent, 0);
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 30000, pendingIntent);

        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        Log.i(TAG, "onDestroy");

        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        am.cancel(pendingIntent);

        stopForeground(true);
    }
}

2. Create a broadcast listener KeepAliveReceiver to receive scheduled broadcasts and restart the resident service:

复制public class KeepAliveReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent service = new Intent(context, KeepAliveService.class);
        context.startService(service);
    }
}

3. Register BroadcastReceiver and corresponding permissions in AndroidManifest.xml:

复制<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<receiver
    android:name=".KeepAliveReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="myAction" />
    </intent-filter>
</receiver>

<service
    android:name=".KeepAliveService"
    android:exported="false" />

You can see that a BroadcastReceiver is registered here to monitor the scheduled tasks of the app. At the same time, the BOOT COMPLETED permission is added and the BOOT COMPLETED broadcast listener is registered to receive the broadcast of the device startup completion.

4. Start the resident service in the onCreate() method of MainActivity:

复制public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent service = new Intent(getApplicationContext(), KeepAliveService.class);
        startService(service);
    }
}

Finally, start the resident service in the onCreate() method of MainActivity to complete the process keep-alive function of the Android application.

5. Keep Alive Framework

When the application enters the background or has not been operated for a long time, the process management mechanism of the Android system will kill its process, so as to avoid system instability or other application problems caused by the long-term occupation of resources by the application. But some applications, such as push and IM applications, need to keep connected in the background, which requires the application process to survive for a long time.

In order to solve this problem, some keep-alive frameworks have emerged in the open source community. Their main function is to keep the application process alive in different ways, ensuring that the application can perform tasks such as connections in the background. Here are some well-known keep-alive frameworks:

  1. Daemon

Daemon is a process guard framework on the Android platform, which includes multiple submodules such as app guard, process keep alive, and service keep alive. Daemon provides different keep-alive methods for different application scenarios, including Service mode, Alarm mechanism, JobScheduler, etc., which can support different keep-alive methods in different Android versions.

GitHub: https://github.com/Leaking/daemon

  1. Xposed

Xposed is a tool for customizing and modifying APK, which allows users to change the behavior and appearance of the application without modifying the APK file, and can also be used to keep the application alive. Xposed uses an in-app module to implement the keep-alive feature, but root permissions are required.

GitHub: https://github.com/rovo89/Xposed

  1. Android-Job

Android-Job is a job scheduling framework on the Android system, a library based on the JobScheduler API. Android-Job allows you to create and execute very easy-to-use jobs. This library makes it very convenient to create short-lived asynchronous tasks or long-running operations.

GitHub: https://github.com/Evernote/android-job

  1. JobSchedulerCompat

JobSchedulerCompat utilizes the JobScheduler API to implement all the functions of JobScheduler in versions below Android 5.0. While implementing JobScheduler, JobSchedulerCompat can support scenarios such as keep-alive.

GitHub: https://github.com/evant/JobSchedulerCompat

  1. WorkManager

WorkManager is a library launched by Google for managing background scheduling tasks, compatible with Api Level 14+ devices. WorkManager is a part of Android Jetpack, combined with WorkManager can easily implement work scheduling and long-running tasks.

GitHub: https://github.com/android/architecture-components-samples/tree/master/WorkManagerSample

The above are some well-known keep-alive frameworks. They all have their own unique characteristics and applicable scenarios, and can be selected and used according to specific development needs.

6. WorkManager

1. Create a WorkManager Worker class:

复制public class KeepAliveWorker extends Worker {
    private static final String TAG = "KeepAliveWorker";

    public KeepAliveWorker(
            @NonNull Context context,
            @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {
        Log.i(TAG, "doWork");

        // 在此添加需要执行的任务
        // ...

        return Result.success();
    }
}

2. Create a timed task and schedule it for execution:

复制PeriodicWorkRequest keepAliveWork =
        new PeriodicWorkRequest.Builder(KeepAliveWorker.class, 15, TimeUnit.MINUTES)
                .setConstraints(Constraints.NONE)
                .build();

WorkManager workManager = WorkManager.getInstance(context);
workManager.enqueueUniquePeriodicWork(
        "keep_alive_work",
        ExistingPeriodicWorkPolicy.KEEP,
        keepAliveWork
);

Here we have created a periodic task that executes every 15 minutes. Execute the task through WorkManager scheduling, where the WorkPolicy is set to ExistingPeriodicWorkPolicy.KEEP means that if a task with the same name is currently being executed, it will remain unchanged and will not be restarted.

3. Declare and apply for some necessary permissions in the AndroidManifest.xml file:

复制<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<application>
    ...

    <receiver
        android:name=".KeepAliveReceiver"
        android:enabled="true"
        android:exported="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>

    ...
</application>

It can be seen that we have registered a BroadcastReceiver in AndroidManifest.xml to receive BOOT_COMPLETED broadcast, so that the task can be automatically restarted after the device is started.

4. Create a BroadcastReceiver to receive the BOOT_COMPLETED broadcast and restart the task:

复制public class KeepAliveReceiver extends BroadcastReceiver {
    private static final String TAG = "KeepAliveReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(new Intent(context, KeepAliveService.class));
        } else {
            context.startService(new Intent(context, KeepAliveService.class));
        }
    }
}

5. Create a resident service to ensure that the application can perform tasks regularly through WorkManager while running in the background:

复制public class KeepAliveService extends Service {
    private static final int NOTIFY_ID = 1001;
    private static final String CHANNEL_ID = "MY_CHANNEL_ID";
    private static final String CHANNEL_NAME = "MY_CHANNEL_NAME";

    private PendingIntent pendingIntent;

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");

        Intent notificationIntent = new Intent(this, MainActivity.class);
        pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

        Notification notification = null;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);

            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            manager.createNotificationChannel(channel);
 notification = new Notification.Builder(this, CHANNEL_ID)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText(getString(R.string.text_keep_alive))
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(false)
                    .setCategory(NotificationCompat.CATEGORY_SERVICE)
                    .build();
        } else {
            notification = new NotificationCompat.Builder(this)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText(getString(R.string.text_keep_alive))
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(false)
                    .setPriority(NotificationCompat.PRIORITY_MIN)
                    .setCategory(NotificationCompat.CATEGORY_SERVICE)
                    .build();
        }

        startForeground(NOTIFY_ID, notification);

        startWorkManager();

        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        Log.i(TAG, "onDestroy");

        stopWorkManager();

        stopForeground(true);

        Intent intent = new Intent(this, KeepAliveReceiver.class);
        intent.setAction("myAction");
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 2000, pendingIntent);
    }

    private void startWorkManager() {
        Log.i(TAG, "startWorkManager");

        PeriodicWorkRequest keepAliveWork =
                new PeriodicWorkRequest.Builder(KeepAliveWorker.class, 15, TimeUnit.MINUTES)
                        .setConstraints(Constraints.NONE)
                        .build();

        WorkManager workManager = WorkManager.getInstance(getApplicationContext());
        workManager.enqueueUniquePeriodicWork(
                "keep_alive_work",
                ExistingPeriodicWorkPolicy.KEEP,
                keepAliveWork
        );
    }

    private void stopWorkManager() {
        Log.i(TAG, "stopWorkManager");

        WorkManager workManager = WorkManager.getInstance(getApplicationContext());
        workManager.cancelUniqueWork("keep_alive_work");
    }
}

We started a resident foreground service (via Notification) in the onStartCommand() method, and called the startWorkManager() method to start the scheduled task of WorkManager. In the onDestroy() method, we call stopWorkManager() to close the task and stop the WorkManager process from running.

It is also worth noting that in the onDestroy() method, we use AlarmManager to start a scheduled broadcast. The purpose is to restart the service through the broadcast when the WorkManager scheduled task is forcibly killed by the system to achieve the effect of keeping alive.

6. Finally, start the Service in the onCreate() method of MainActivity:

复制public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent service = new Intent(getApplicationContext(), KeepAliveService.class);
        startService(service);
    }
}

This completes the example of using WorkManager to implement Android application process keep-alive.

seven,

  • Daemon realizes the access scheme of application process keeping alive
  • Ok, the following is an example of using Daemon to implement Android application process keep alive:

    1. Import dependencies in the build.gradle file:

    复制repositories {
        maven { url "https://jitpack.io" }
    }
    
    dependencies {
        implementation 'com.github.Leaking:Daemon:2.1.13'
    }
    

    2. Create a custom Service that inherits from DaemonInnerService. DaemonInnerService is a basic service provided in the Daemon library, which is used to start a resident process in the background.

    复制public class MyService extends DaemonInnerService {
        private static final String TAG = "MyService";
    
        // ...
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.i(TAG, "onCreate");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.i(TAG, "onStartCommand");
            startWork();
    
            return START_STICKY;
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
    
            Log.i(TAG, "onDestroy");
            stopWork();
        }
    
        // ...
    }
    

    The MyService we created here inherits DaemonInnerService and overrides the onStartCommand() and onDestroy() methods. It should be noted that we call the startWork() method in onStartCommand(), which is used to start some tasks that need to be kept alive. At the same time, in the onDestroy() method, we call the stopWork() method to stop the keep-alive task.

    3. Register the service in the AndroidManifest.xml file:

    复制<service
        android:name=".MyService"
        android:enabled="true"
        android:exported="false" />
    
    <receiver
        android:name=".MyReceiver"
        android:priority="1000"
        android:exported="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <action android:name="android.intent.action.USER_PRESENT" />
        </intent-filter>
    </receiver>
    

    Here we also registered a broadcast receiver MyReceiver to receive BOOT COMPLETED and USER PRESENT broadcasts, and start the service when the device is booted or unlocked.

    4. Create a keep alive delay task class to perform keep alive related operations:

    复制public class MyDelayService extends AbsWorkService {
        private static final String TAG = "MyDelayService";
    
        @Override
        public Boolean shouldStopService(Intent intent, int flags, int startId) {
            Log.i(TAG, "shouldStopService");
            return super.shouldStopService(intent, flags, startId);
        }
    
        @Override
        public void startWork(Intent intent, int flags, int startId) {
            Log.i(TAG, "startWork");
    
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
    _
    
        Intent service = new Intent(getApplicationContext(), MyService.class);
                startService(service);
                startDaemonService(MyDelayService.class);
            }, 10000);
        }
    
        @Override
        public void stopWork(Intent intent, int flags, int startId) {
            Log.i(TAG, "stopWork");
            stopDaemonService(MyDelayService.class);
        }
    
        @NonNull
        @Override
        public Result onRunTask(Intent intent, int flags, int startId) {
            Log.i(TAG, "onRunTask");
    
            return Result.SUCCESS;
        }
    }
    
    In MyDelayService, we define a startWork() method, in which MyService needs to be started manually, and the service whose DaemonInnerService type is MyDelayService needs to be started. At the same time, it should be noted that the task needs to be executed after 10 seconds to ensure that the startWork() method can be called after the service startup is completed. 
    
    5. Create a broadcast receiver MyReceiver to receive system broadcasts and restart the keep-alive service:
  • 复制public class MyReceiver extends AbsReceiver {
        private static final String TAG = "MyReceiver";
    
        @Override
        public void onReceive(Context context, Intent intent) {
            super.onReceive(context, intent);
    
            Log.i(TAG, "onReceive");
    
            boolean isScreenOn = isScreenOn(context);
    
            if (isScreenOn) {
                Intent service = new Intent(context, MyService.class);
                context.startService(service);
            }
        }
    }
    

    In MyReceiver, we judge whether the device is unlocked according to the broadcast type, and restart the service according to the result. Note that here we need to use the isScreenOn() method to determine whether the device is unlocked, and this method needs to be implemented in AbsReceiver.

    6. Finally, start the keep alive service in MainActivity:

    复制public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Intent service = new Intent(getApplicationContext(), MyService.class);
            startService(service);
        }
    }
    

    The above is an example of using Daemon to implement Android application process keep-alive. Through the Daemon library, we can implement the application process keep-alive function very simply, support keep-alive in different scenarios, and can pass

Guess you like

Origin blog.csdn.net/MYBOYER/article/details/129945121