Android has four major components: first activity, broadcast receiver, content provider, and services. Tasks that run in the background, like downloading a large file, use services. Services are designed to do some work without a user interface. Services are used for Interprocess Communication (IPC) between Android applications. For example, playing music, network transactions, performing file I/O, etc, all in the background.
We must declare all services in the manifest file.
In the <application> element we can add the <service> element as its child.
1 2 3 4 5 6
<manifest ... > <application ... > <service android:name=".MyService" /> ... </application> </manifest>
There are three types of services:
Foreground Services: Most of the time we need operations that are noticeable to us. Such operations are performed by foreground services.
Example: Playing music in an application like Spotify is a foreground service.
Background Services: Sometimes we need operations to be performed in the background. Such operations are handled by background services. Example: Scheduled syncing of data.
Bound Services: bindServices()
is called when the application gets bound with services. We need an interface that can allow interaction between the components and other things like service, receive results, send requests, and interaction across processes, with the help of IPC. Such a client-server interface is provided by bound services. This type of service runs until other application components are attached, or bound, to them. Multiple components can be bound to a service and in this case, the service only dies when all of these multiple components unbind from the service.
There are two different types of service lifecycle in Android.
Started Service: When an application component calls startService()
then service will start. This type of service does not return any result and performs only a single operation. The component which has started this service gets destroyed, then this service runs in the background.
Started service can be stopped in two ways:
> stopService()
method
> stopSelf()
method
Bound service: We can consider this service a server in the client-server interface. Bound services are services that are bound with the application component with the help of the bindService()
method. If we need to stop such service then the unbindService()
method needs to be called, which unbinds all the components from the service.
We can describe service behavior as a sequence of events occurring in multiple states.
There are a few important methods in the services life cycle.
onCreate(): The onCreate()
method is called automatically by the activity manager after the service gets started. We can use this service for the role of the virtual constructor.
onDestroy(): It is called when the service is no longer used and is destroyed. We can use this service for cleaning purposes. It can be helpful in various places by cleaning up receivers, threads, registered listeners, etc.
onUnbind(): onUnbind()
method is used to handle the intent object, and it unbinds the clients. This method can call onRebind() when a new client is connected with the service.
onRebind(): It is called when new clients have connected to the service after it had previously been notified that all had disconnected in its onUnbind()
.
onBind(): Bound service is initiated by a client, like an activity, by calling bind service and as a result the service gets started, if it is not already running. At this stage the activity manager automatically calls onCreate()
and onBind()
hook methods. In order to allocate some kind of IPC channel which can pass back to the client, we need the onBind()
method to act as the handshake between the client and the service in place.
onStartCommand(): When a client component, like an activity, calls to start service, the Android activity manager starts the service beginning in the starting state. The activity manager service can call onStartCommand()
again when the initialization is complete and also when the service is up and in a running state. Then in this stage, it passes the intent that was provided by the client component when it called to begin service; this could then proceed further and process whatever it must to handle the intent. Often start service calls result in the call of onStartCommand() (if the service has not been shut down in this period of time). But due to this, there might be a case when it gets called multiple times for processing multiple intents at some point. This service can be shut down in different ways like by calling stopSelf()
, which is called voluntarily by itself, or by calling stopService()
by a client, or the Android system may involuntarily shut down.
AndroidManifest.xml
1 2 3 4 5 6 7 8 9
<<manifest ... > <uses-permission android:name="android.permission.INTERNET"/> <application ... > <service android:name=".My_Musice" android:enabled="true" android:exported="false"></service> ... </application> </manifest>
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <ImageView android:id="@+id/implay" android:layout_width="200sp" android:layout_height="200sp" android:layout_gravity="center_horizontal" android:layout_marginTop="10sp" android:contentDescription="TODO" app:srcCompat="@drawable/play" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/bplay" android:text="Play" android:layout_gravity="center_horizontal"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/bpush" android:text="Stop" android:layout_gravity="center_horizontal" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/bnext" android:text="Next page" android:layout_gravity="center_horizontal"/> </LinearLayout>
MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package com.example.musicapp;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements MuiseStopped {
ImageView implay;
String aduiolink = "https://1drv.ms/u/s!AlkGhfSpdPmCg2Vqbsid4n0D5bK";
boolean musicePlaying = false;
Intent servierIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
implay = findViewById(R.id.implay);
implay.setBackgroundResource(R.drawable.play);
servierIntent = new Intent(this, My_Musice.class);
ApplicationClass.context = (Context) MainActivity.this;
implay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!musicePlaying) {
playAduio();
implay.setImageResource(R.drawable.pause);
musicePlaying = true;
} else {
stopPlayAduio();
implay.setImageResource(R.drawable.play);
musicePlaying = false;
}
}
});
}
private void stopPlayAduio() {
try {
stopService(servierIntent);
} catch (SecurityException se) {
Toast.makeText(this, "Error :" + se.getMessage(), Toast.LENGTH_SHORT)
.show();
}
}
private void playAduio() {
servierIntent.putExtra("Adiolink", aduiolink);
try {
startService(servierIntent);
} catch (SecurityException e) {
Toast.makeText(this, "Error :" + e.getMessage(), Toast.LENGTH_SHORT)
.show();
}
}
@Override
public void onMuiseStopped() {
implay.setImageResource(R.drawable.play);
musicePlaying = false;
}
}
MusicStopped(Interface)
package com.example.musicapp;
public interface MuiseStopped {
void onMuiseStopped();
}
My_Music.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package com.example.musicapp;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.widget.Toast;
public class My_Musice extends Service implements MediaPlayer.OnCompletionListener,
MediaPlayer.OnPreparedListener,
MediaPlayer.OnErrorListener,
MediaPlayer.OnSeekCompleteListener,
MediaPlayer.OnInfoListener,
MediaPlayer.OnBufferingUpdateListener {
private MediaPlayer mediaPlayer;
String link;
private MuiseStopped muiseStopped;
public My_Musice() {}
@Override
public void onCreate() {
super.onCreate();
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnSeekCompleteListener(this);
mediaPlayer.setOnInfoListener(this);
mediaPlayer.setOnBufferingUpdateListener(this);
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
muiseStopped = (MuiseStopped) ApplicationClass.context;
link = intent.getStringExtra("Audiolink");
mediaPlayer.reset();
if (!mediaPlayer.isPlaying()) {
try {
mediaPlayer.setDataSource(link);
mediaPlayer.prepareAsync();
} catch (Exception e) {
Toast.makeText(this, "Error :" + e.getMessage(), Toast.LENGTH_SHORT)
.show();
}
}
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
}
}
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
muiseStopped.onMuiseStopped();
stopSelf();
}
@Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
switch (i) {
case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
Toast.makeText(this, "MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK", Toast.LENGTH_SHORT)
.show();
break;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
Toast.makeText(this, "MEDIA_ERROR_SERVER_DIED", Toast.LENGTH_SHORT)
.show();
break;
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
Toast.makeText(this, "MEDIA_ERROR_UNKNOWN", Toast.LENGTH_SHORT)
.show();
break;
}
return false;
}
@Override
public boolean onInfo(MediaPlayer mediaPlayer, int i, int i1) {
return false;
}
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
@Override
public void onSeekComplete(MediaPlayer mediaPlayer) {}
@Override
public void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {}
}
Output