[JAVA] Programmation à partir de 51 ans Remarque: ne démarrez pas Android Sevice plus d'une fois Confirmation du démarrage du service

J'ai créé un programme qui dit "Lorsque vous appuyez sur le bouton de démarrage de MainActivity, le service démarre", et chaque fois que vous appuyez sur le bouton de démarrage, plusieurs services démarrent! .. C'est donc un rappel sur la façon d'éviter les bottes en double.

La méthode d'utilisation de la méthode ActivityManager.RunningServiceInfo () semble être obsolète </ font>, et chaque méthode d'ActivityManager est utilisée dans le processus de développement tel que le débogage. , C'était une référence pour ne pas l'utiliser dans le code qui exécute l'application terminée, est-ce donc judicieux de ne pas utiliser la méthode ActivityManager?

Exemple de code de confirmation de comportement

Aperçu de l'exemple de code

  1. API26

  2. ** Fichiers principaux **
    MainActivity.java
    MyService.java: étend le service

  3. MainActivity.java ■ Bouton Démarrer. Événement de clic:
    Reportez-vous à la variable globale MyServiceState de MyService.class et démarrez MyService.java lorsque MyServiceState == false
    ■ Bouton Arrêter. Cliquez sur l'événement: exécutez
    stopService () pour arrêter MyService.class

  4. ** MyService.java **
    Variable globale: public static boolean Set MyServiceState = false;
    When onCreate (): Replace with MyServiceState = true;
    onStartCommand (): Run Log ..
    onDestroy (): Remplacez par MyServiceState = false;

■ Explication Déclarez les variables globales et statiques dans MyService.class. La valeur de cette variable détermine si le service est en cours d'exécution. Dans le code ci-dessous, la variable est définie sur une valeur booléenne, et si elle est fausse, elle n'est pas démarrée, et si elle est vraie, elle est démarrée. En se référant à la valeur de la variable MyService.class d'ActivityMain.class, il est jugé si le service est démarré ou non.

■ Confirmation du comportement Si vous définissez MyServiceState = false; </ font> dans onCreate () de MyService.class, le journal sera lu chaque fois que vous appuyez sur le bouton de démarrage. Si vous définissez MyServiceState = true; </ font>, le journal ne circulera qu'une seule fois, quel que soit le nombre de fois que vous appuyez sur le bouton de démarrage (MyService sera détruit lorsque vous appuyez sur le bouton d'arrêt, donc à nouveau. Vous pouvez jouer à Log une fois avec le bouton de démarrage)

(Mise en garde) API26 et versions ultérieures planteront si le service n'est pas démarré sans notification et exécution de startForeground () </ strong> dans les 5 secondes </ font>. Dans le code ci-dessous, si vous définissez la notification, le code sera long et difficile à voir, de sorte que le traitement des notifications n'est pas effectué en raison de plantages. Ce code sert uniquement à vérifier le comportement de ne pas démarrer le service deux fois. Ajoutez le code de non-crash correspondant à l'API 16 à 29 à la fin ([Exemple de code d'application résidente compté par Log]).

Avec cela, le code commence ci-dessous!

Exemple de code de confirmation de comportement


ActivityMain.java

ActivityMain.java


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

    Button btn_start = findViewById(R.id.btn_start);
    Button btn_stop  = findViewById(R.id.btn_stop);

    final Intent intent = new Intent(this,MyService.class);
    btn_start.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            // MyService.Reportez-vous à la variable MyServiceState de la classe
            // MyServiceState=Si faux, démarrez le service
            if(MyService.MyServiceState == false){
                startForegroundService(intent);
            }
        }
    });

    btn_stop.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            stopService(intent);
        }
    });
}

MyService.java

MyService.java


public class MyService extends Service {
    //Déclarez la variable statique globale MyServiceState avec une valeur initiale de false
    // onCreate()En substituant vrai dans
    //Vous pouvez déterminer si le service est onCreate en vous référant à MyServiceState.
    public static boolean MyServiceState = false;

    public MyService() {
    }

    @Override
    public void onCreate(){
        super.onCreate();
        //Définir le MyServiceState statique global sur true
        MyServiceState = true;
    }

    @Override
    public int onStartCommand(Intent intent,int flags,int startId){
        Log.d("Service","Started");
        return START_NOT_STICKY;
    }

    @Override 
    public void onDestroy(){
        super.onDestroy();
        MyServiceState = false;
    }

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

Exemple de code d'application résidente à compter dans le journal

SDK cible API29
SDK minimum API16
Manifeste ajouté uses-permission android: name = "android.permission.FOREGROUND_SERVICE"
Fichiers principaux MainActivity.java
MyService.java
Autre Définissez le contenu de la notification. L'icône de notification est votre choix

■ Explication Le code ci-dessous, contrairement à l'exemple de code ci-dessus, confirme la version de l'API de 16 à 29. J'ai mis une notification dans la zone de notification pour éviter qu'elle ne plante.

Lorsque vous appuyez sur Démarrer sur l'écran de l'interface utilisateur, un message de comptage sera lu dans le journal, un bouton d'arrêt arrêtera le message et Start relira un message de comptage. Même si vous appuyez continuellement sur le bouton de démarrage, le message de comptage ne sera pas dupliqué.

Puis, tout en étant enfantin (honte) MainActivity.java

MainActivity.java


public class MainActivity extends AppCompatActivity {

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

        Button btn_start = findViewById(R.id.btn_start);
        Button btn_stop  = findViewById(R.id.btn_stop);

        final Intent intent = new Intent(this,MyService.class);
        //Bouton Start
        //Démarrez MyService si l'état de la variable MyService est faux
        btn_start.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                if(MyService.state == false){
                    if(Build.VERSION.SDK_INT >=26){
                        startForegroundService(intent);
                    }else{
                        startService(intent);
                    }
                }
            }
        });

        //Bouton d'arrêt
        btn_stop.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                stopService(intent);
            }
        });
    }
}

MyService.java

MyService.java


public class MyService extends Service {
    //Variables qui déterminent l'état du thread
    //Le fil démarre lorsque le signal est vrai, s'arrête lorsqu'il est faux
    //défini sur true avec onCreate et false avec onDestroy
    private boolean signal;

    //Variable qui détermine s'il faut démarrer MyService
    public static boolean state = false;

    public MyService() {
    }

    @Override
    public void onCreate(){
        super.onCreate();
        state = true;
    }

    @Override
    public int onStartCommand(Intent intent,int flags,int startId){
        //Création de contenu de notification et émission de notifications
        Notification notification;
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this,"id");
        Intent intentm = new Intent(this,MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intentm,0);
        notification = builder.setSmallIcon(R.drawable.notification_icon)
                              .setContentTitle("title")
                              .setContentText("text")
                              .setContentIntent(pendingIntent)
                              .build();

        if(Build.VERSION.SDK_INT >=26){
            int importance = NotificationManager.IMPORTANCE_LOW;
            NotificationChannel channel = new NotificationChannel("id","name",importance);
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
            startForeground(1,notification);
        }else{
            notification = builder.setPriority(NotificationCompat.PRIORITY_LOW).build();
            NotificationManagerCompat managerCompat = NotificationManagerCompat.from(this);
            managerCompat.notify(1,notification);
        }//Ceci est le code d'émission de notification

        signal = true;
        startThread();
        return START_NOT_STICKY;
    }

    //Thread qui continue d'exécuter le journal
    public void startThread(){
        new Thread(new Runnable(){
            @Override
            public void run() {
                int i=0;

                //Fonctionne jusqu'à ce que le signal soit faux sur onDestroy
                while(signal){
                    try {
                        sleep(1000);
                        Log.d("COUNT", String.valueOf(i));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    i++;
                }
            }
        }).start();
    }

    @Override
    public void onDestroy(){
        super.onDestroy();
        //Émettre un signal d'arrêt de fil
        signal = false;

        //Représente l'état inactif du service
        state  = false;
    }

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

Recommended Posts