[JAVA] Programming from 51 years old Note: Do not start Android Sevice more than once Service start confirmation

I made a program that says "When you press the start button of MainActivity, Service starts", and every time you press the start button, multiple Services start! .. So it's a reminder of how to avoid duplicate boots.

The method of using the ActivityManager.RunningServiceInfo () method seems to be deprecated </ font>, and each method of ActivityManager is used in the development process such as debugging. , It was a reference not to use it in the code that runs the completed application, so is it sound to not use the ActivityManager method?

Behavior check sample code

Sample code overview

  1. API26

  2. ** Main files **
    MainActivity.java
    MyService.java: extends Service

  3. MainActivity.java ■ Start button. Click event:
    Refer to the global variable MyServiceState of MyService.class and start MyService.java when MyServiceState == false
    ■ Stop button. Click event: Execute
    stopService () to stop MyService.class

  4. ** MyService.java **
    Global variable: set public static boolean MyServiceState = false;
    When onCreate (): Replace with MyServiceState = true;
    onStartCommand (): Run Log ..
    onDestroy (): Replace with MyServiceState = false;

■ Explanation Declare a global and static variable in MyService.class. The value of that variable determines whether the Service is running. In the code below, the variable is set to a boolean value, and if false, it is not started, if true, it is started. By referring to the value of the variable of MyService.class from ActivityMain.class, it is judged whether Service is started or not.

■ Confirmation of behavior If you set MyServiceState = false; </ font> in onCreate () of MyService.class, Log will be played every time you press the start button. If you set MyServiceState = true; </ font>, Log will only flow once no matter how many times you press the start button (MyService will be destroyed when you press the stop button, so again. You can play Log once with the start button)

(Caution) API26 and above will crash if Service is not started without notification and startForeground () </ strong> execution within 5 seconds </ font>. In the code below, if you set the notification, the code will be long and difficult to see, so notification processing is not performed due to a crash or the like. This code is just for checking the behavior of not starting the service twice. Add the non-crash code corresponding to API 16 to 29 at the end ([Sample code of resident application counted by Log]).

With that, the code starts below!

Behavior confirmation sample code


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.Reference the MyServiceState variable of class
            // MyServiceState=If false, start 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 {
    //Declare the global static variable MyServiceState with an initial value of false
    // onCreate()By substituting true in
    //You can determine if Service is onCreate by referring to MyServiceState.
    public static boolean MyServiceState = false;

    public MyService() {
    }

    @Override
    public void onCreate(){
        super.onCreate();
        //Set global static MyServiceState to 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;
    }
}

Sample code of resident application to count in Log

Target SDK API29
Minimum SDK API16
Manifest added uses-permission android: name = "android.permission.FOREGROUND_SERVICE"
Main files MainActivity.java
MyService.java
Other Set the notification content. Notification icon is your choice

■ Explanation The code below, unlike the sample code above, confirms the API version from 16 to 29. I put a notification in the notification area to prevent it from crashing.

When you press Start on the UI screen, a count message will be played in Log, a stop button will stop the message, and Start will play a count message again. Even if you push the start button continuously, the count message will not be duplicated.

Then, while being childish (shame) 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);
        //Start button
        //Start MyService if the MyService variable state is false
        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);
                    }
                }
            }
        });

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

MyService.java

MyService.java


public class MyService extends Service {
    //Variables that determine the state of threads
    //Thread starts when signal true, stops when false
    //Set to true with onCreate and false with onDestroy
    private boolean signal;

    //Variable that determines whether to start 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){
        //Creating notification content and issuing 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);
        }//This is the notification issuance code

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

    //Thread that keeps running Log
    public void startThread(){
        new Thread(new Runnable(){
            @Override
            public void run() {
                int i=0;

                //Runs until signal false on 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();
        //Issue thread stop signal
        signal = false;

        //Represents service inactive state
        state  = false;
    }

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

Recommended Posts