Solución de mantenimiento del proceso de aplicación de Android en la práctica

  1. Servicio en primer plano: configure el servicio que ejecuta la aplicación como un servicio en primer plano para que el usuario sepa que la aplicación se está ejecutando en segundo plano, y el sistema le dará cierta prioridad para reducir la probabilidad de que el sistema lo elimine. Sin embargo, debe tenerse en cuenta que el uso del servicio de primer plano para mantenerse vivo no puede ocupar una gran cantidad de la barra de notificaciones del usuario, de lo contrario, el usuario puede sentirse molesto y desinstalar la aplicación.

  2. JobScheduler: un método de programación de tareas introducido en Android 5.0, que puede organizar de manera flexible el tiempo de ejecución de tareas de la aplicación y mejorar la eficiencia y la estabilidad de la ejecución de tareas.

  3. AlarmManager: puede iniciar el servicio o transmitir la aplicación regularmente en segundo plano para garantizar que el sistema no elimine la aplicación en segundo plano. Pero al mismo tiempo, también debemos prestar atención para evitar el uso excesivo de AlarmManager y reducir el consumo de energía y la ocupación de recursos de las aplicaciones en segundo plano.

  4. Protección de proceso dual: al abrir dos procesos, la aplicación ejecuta dos procesos diferentes en el sistema para protegerse entre sí, asegurando que una vez que el sistema destruya un proceso, el otro proceso activará la aplicación nuevamente. Sin embargo, el daemon de proceso dual provocará un uso elevado de la memoria de la aplicación y algunos fabricantes de teléfonos móviles pueden desactivar esta función.

  5. Marco Keep-Alive: hay algunos marcos Keep-Alive de terceros en el mercado, que pueden mantener la actividad de la aplicación a través de algunos medios técnicos, como el uso de la CPU, el bloqueo de activación, etc. Sin embargo, debe tenerse en cuenta que estos marcos pueden causar un consumo adicional de recursos y consumo de energía.

Las anteriores son las principales soluciones para mantener vivo el proceso de aplicación de Android. Por supuesto, las políticas de mantenimiento de vida de diferentes aplicaciones pueden variar debido a las características de la aplicación y las necesidades de desarrollo.

1. Servicio de recepción

1. Agregue permisos para acceder al estado de la red y servicios en primer plano en el archivo AndroidManifest.xml:

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

2. Cree un servicio en segundo plano, deje que Service herede la clase Service, implemente su método onBind() y su método onStartCommand(), mantenga el servicio ejecutándose en primer plano y vuelva a iniciarlo cuando se destruya el servicio:

复制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. Inicie el servicio en la clase MainActivity:

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

Se usa un PendingIntent en la barra de notificaciones en el servicio de primer plano para iniciar MainActivity, de modo que el usuario pueda abrir la aplicación al hacer clic en la barra de notificaciones. Cuando se destruye el servicio, el servicio se reinicia iniciando otro objeto Intent, realizando así la función de mantenimiento. Cabe señalar que el servicio continuará ejecutándose después de que el programa salga, y el servicio debe detenerse llamando al método stopService() o al método stopForeground(), de lo contrario, puede continuar ejecutándose en segundo plano y aumentar el sistema. carga.

Dos, guardián de proceso dual

  • 1. Cree una clase de servicio daemon 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. Cree una clase de servicio en vivo 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. Inicie el servicio de guardián y extraiga el servicio en 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));
        }
    }
    

    Si el sistema elimina la aplicación, captúrela en tiempo real e intente llamar a ProtectService para activar la aplicación, deje que se ejecute en primer plano nuevamente y asegúrese de que rara vez se elimine en segundo plano. Al mismo tiempo, dado que el servicio de primer plano está activado, cambiar entre el primer plano y el segundo plano con frecuencia puede generar una gran cantidad de "notificaciones de residentes" en la barra de notificaciones del usuario, a las que se debe prestar atención.

  • Agregue la función de iniciar el teléfono móvil a las funciones anteriores
  • Ok, el siguiente es un ejemplo de código completo para agregar la función de inicio del teléfono móvil basado en la solución anterior:

    1. Cree una clase BroadcastReceiver para monitorear la transmisión de arranque del teléfono móvil y cree un objeto Intent para iniciar el servicio guardián y extraer el servicio:

    复制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. Registre los permisos y BroadcastReceiver en el archivo AndroidManifest.xml:

    复制<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. En la clase MainActivity, verifique si el servicio daemon y el servicio en vivo se están ejecutando y, de no ser así, inícielos manualmente:

    复制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;
        }
    }
    

    Lo anterior es un ejemplo de código completo para agregar la función de inicio del teléfono móvil, que puede iniciar automáticamente el servicio después de reiniciar el dispositivo y mantener el estado de ejecución de la aplicación en segundo plano.

三、Programador de trabajos

1. Cree una clase JobService e implemente sus métodos onStartJob() y onStopJob():

复制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. Registre JobService y los permisos necesarios en el archivo AndroidManifest.xml:

复制<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. Invoque el JobScheduler correspondiente cuando la aplicación comience a realizar 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.");
        }
    }
}

Aquí configuramos el tiempo de actividad en 10 segundos y configuramos la solicitud de red para que no distinga entre Wifi o red móvil. Después de reciclar la aplicación, JobScheduler reiniciará la aplicación e invocará el método onStartJob() de la clase MyJobService, y agregará tareas que se ejecutarán en este método para completar el mantenimiento de la aplicación.

Cabe señalar que JobScheduler no está 100% garantizado para poder ejecutar tareas con precisión de acuerdo con el tiempo establecido. El sistema puede retrasar el tiempo de ejecución de las tareas por algunas razones, y las diferentes versiones de Android pueden tener diferentes niveles de soporte.

Si la tarea requiere una ejecución inmediata, puede usar el método startService() o ForegroundService para implementarlo y usarlo junto con JobScheduler para asegurarse de que no se elimine en segundo plano.

4. Administrador de alarmas

1. Cree un servicio de proceso residente e implemente sus métodos onBind(), onStartCommand() y onDestroy():

复制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. Cree un receptor de transmisión KeepAliveReceiver para recibir transmisiones programadas y reinicie el servicio residente:

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

3. Registre BroadcastReceiver y los permisos correspondientes en 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" />

Puede ver que un BroadcastReceiver está registrado aquí para monitorear las tareas programadas de la aplicación. Al mismo tiempo, se agrega el permiso BOOT COMPLETED y el oyente de transmisión BOOT COMPLETED se registra para recibir la transmisión de la finalización del inicio del dispositivo.

4. Inicie el servicio residente en el método onCreate() de 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);
    }
}

Finalmente, inicie el servicio residente en el método onCreate() de MainActivity para completar la función de mantenimiento del proceso de la aplicación de Android.

5. Mantener vivo el marco

Cuando la aplicación entra en segundo plano o no se ha utilizado durante mucho tiempo, el mecanismo de gestión de procesos del sistema Android eliminará su proceso para evitar la inestabilidad del sistema u otros problemas de la aplicación causados ​​por la ocupación a largo plazo de los recursos por parte del solicitud. Pero algunas aplicaciones, como las aplicaciones push y IM, deben mantenerse conectadas en segundo plano, lo que requiere que el proceso de la aplicación sobreviva durante mucho tiempo.

Para solucionar este problema, han surgido en la comunidad de código abierto algunos frameworks keep-alive cuya función principal es mantener vivo el proceso de la aplicación de diferentes maneras, asegurando que la aplicación pueda realizar tareas como conexiones en segundo plano. Aquí hay algunos marcos de mantenimiento de vida conocidos:

  1. Demonio

Daemon es un marco de protección de procesos en la plataforma Android, que incluye varios submódulos, como protección de aplicaciones, mantenimiento de procesos y mantenimiento de servicios. Daemon proporciona diferentes métodos de mantenimiento de actividad para diferentes escenarios de aplicaciones, incluidos el modo de servicio, el mecanismo de alarma, JobScheduler, etc., que pueden admitir diferentes métodos de mantenimiento de actividad en diferentes versiones de Android.

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

  1. Xpuesto

Xposed es una herramienta para personalizar y modificar APK, que permite a los usuarios cambiar el comportamiento y la apariencia de la aplicación sin modificar el archivo APK, y también se puede utilizar para mantener viva la aplicación. Xposed usa un módulo en la aplicación para implementar la función de mantenimiento, pero se requieren permisos de root.

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

  1. Android-trabajo

Android-Job es un marco de programación de trabajos en el sistema Android, una biblioteca basada en la API JobScheduler. Android-Job le permite crear y ejecutar trabajos muy fáciles de usar. Esta biblioteca lo hace muy conveniente para crear tareas asíncronas de corta duración u operaciones de larga duración.

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

  1. JobSchedulerCompat

JobSchedulerCompat utiliza la API de JobScheduler para implementar todas las funciones de JobScheduler en versiones anteriores a Android 5.0. Mientras implementa JobScheduler, JobSchedulerCompat puede admitir escenarios como el de mantenimiento de vida.

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

  1. administrador de trabajo

WorkManager es una biblioteca lanzada por Google para administrar tareas de programación en segundo plano, compatible con dispositivos Api Level 14+. WorkManager es parte de Android Jetpack, combinado con WorkManager puede implementar fácilmente la programación del trabajo y las tareas de ejecución prolongada.

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

Los anteriores son algunos marcos de mantenimiento de vida bien conocidos. Todos ellos tienen sus propias características únicas y escenarios aplicables, y se pueden seleccionar y usar de acuerdo con las necesidades de desarrollo específicas.

6. Administrador de trabajo

1. Cree una clase WorkManager Worker:

复制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. Cree una tarea cronometrada y programe su ejecución:

复制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
);

Aquí hemos creado una tarea periódica que se ejecuta cada 15 minutos. Ejecute la tarea a través de la programación de WorkManager, donde WorkPolicy se establece en ExistingPeriodicWorkPolicy.KEEP significa que si una tarea con el mismo nombre se está ejecutando actualmente, permanecerá sin cambios y no se reiniciará.

3. Declare y solicite algunos permisos necesarios en el archivo AndroidManifest.xml:

复制<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>

Se puede ver que hemos registrado un BroadcastReceiver en AndroidManifest.xml para recibir la transmisión BOOT_COMPLETED, de modo que la tarea se pueda reiniciar automáticamente después de que se inicie el dispositivo.

4. Cree un BroadcastReceiver para recibir la transmisión BOOT_COMPLETED y reinicie la tarea:

复制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. Cree un servicio residente para asegurarse de que la aplicación pueda realizar tareas regularmente a través de WorkManager mientras se ejecuta en segundo plano:

复制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");
    }
}

Iniciamos un servicio de primer plano residente (a través de Notificación) en el método onStartCommand() y llamamos al método startWorkManager() para iniciar la tarea programada de WorkManager. En el método onDestroy(), llamamos a stopWorkManager() para cerrar la tarea y detener la ejecución del proceso WorkManager.

También vale la pena señalar que en el método onDestroy(), usamos AlarmManager para iniciar una transmisión programada. El propósito es reiniciar el servicio a través de la transmisión cuando el sistema cancela por la fuerza la tarea programada de WorkManager para lograr el efecto de mantener viva. .

6. Finalmente, inicia el Servicio en el método onCreate() de 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);
    }
}

Esto completa el ejemplo del uso de WorkManager para implementar el proceso de aplicación de Android.

Siete,

  • Daemon realiza el esquema de acceso del proceso de aplicación manteniendo vivo
  • Ok, el siguiente es un ejemplo del uso de Daemon para implementar el proceso de aplicación de Android para mantener vivo:

    1. Importar dependencias en el archivo build.gradle:

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

    2. Cree un Servicio personalizado que herede de DaemonInnerService. DaemonInnerService es un servicio básico proporcionado en la biblioteca Daemon, que se utiliza para iniciar un proceso residente en segundo plano.

    复制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();
        }
    
        // ...
    }
    

    El MyService que creamos aquí hereda DaemonInnerService y anula los métodos onStartCommand() y onDestroy(). Cabe señalar que llamamos al método startWork() en onStartCommand(), que se utiliza para iniciar algunas tareas que deben mantenerse activas. Al mismo tiempo, en el método onDestroy(), llamamos al método stopWork() para detener la tarea de mantenimiento.

    3. Registre el servicio en el archivo AndroidManifest.xml:

    复制<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>
    

    Aquí también registramos un receptor de transmisión MyReceiver para recibir transmisiones BOOT COMPLETED y USER PRESENT, e iniciar el servicio cuando el dispositivo se inicia o desbloquea.

    4. Cree una clase de tarea de retraso para mantener activo para realizar operaciones relacionadas con mantener activo:

    复制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); 
                iniciarServicio(servicio); 
                startDaemonService(MyDelayService.class); 
            }, 10000); 
        } 
    
        @Override 
        public void stopWork(Intento, 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"); 
    
            volver Resultado.ÉXITO; 
        } 
    }
    
    En MyDelayService, definimos un método startWork(), en el que MyService debe iniciarse manualmente y el servicio cuyo tipo DaemonInnerService es MyDelayService debe iniciarse. Al mismo tiempo, se debe tener en cuenta que la tarea debe ejecutarse después de 10 segundos para garantizar que se pueda llamar al método startWork() después de que se complete el inicio del servicio. 
    
    5. Cree un receptor de transmisión MyReceiver para recibir transmisiones del sistema y reinicie el servicio de mantenimiento:
  • 复制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);
            }
        }
    }
    

    En MyReceiver, juzgamos si el dispositivo está desbloqueado según el tipo de transmisión y reiniciamos el servicio según el resultado. Tenga en cuenta que aquí necesitamos usar el método isScreenOn() para determinar si el dispositivo está desbloqueado, y este método debe implementarse en AbsReceiver.

    6. Finalmente, inicie el servicio de mantenimiento activo en 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);
        }
    }
    

    Lo anterior es un ejemplo del uso de Daemon para implementar el proceso de aplicación de Android. A través de la biblioteca Daemon, podemos implementar la función keep-alive del proceso de la aplicación de manera muy simple, admitir keep-alive en diferentes escenarios y podemos pasar

Supongo que te gusta

Origin blog.csdn.net/MYBOYER/article/details/129945121
Recomendado
Clasificación