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?
API26
** Main files **
MainActivity.java
MyService.java: extends Service
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
** 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!
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;
}
}
Target SDK td> | API29 td> |
Minimum SDK td> | API16 td> |
Manifest added td> | uses-permission android: name = "android.permission.FOREGROUND_SERVICE" td> |
Main files td> | MainActivity.java MyService.java td> |
Other td> | Set the notification content. Notification icon is your choice td> |
■ 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