audio player service stops when phone sleeps [duplicate] - java

This question already has answers here:
How can we prevent a Service from being killed by OS?
(11 answers)
Background service stops after 20 sec after destroy app in Android 10 java
(1 answer)
Closed 1 year ago.
I am running audio player service but If I put my phone on sleep the player stops or the background service I don't know what's the problem.
this is my music service class :
public class MusicService extends Service {
public static final String ACTION_NEXT = "NEXT";
public static final String ACTION_PREV = "PREVIOUS";
public static final String ACTION_PLAY = "PLAY";
public static final String ACTION_FORWARD = "FORWARD";
public static final String ACTION_REWIND = "REWIND";
public static final String ACTION_CONTINUE = "CONTINUE";
ActionPlaying actionPlaying;
Action action;
private final IBinder mBinder = new MyBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class MyBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String actionName = intent.getStringExtra("myActionName");
if (actionName != null) {
switch (actionName)
{
case ACTION_PLAY:
if(actionPlaying!= null){
if(action!= null){
actionPlaying.playClicked();
action.playPauseClicked();
}}
break;
case ACTION_NEXT:
if(actionPlaying != null){
actionPlaying.nextClicked();
}
break;
case ACTION_PREV:
if(actionPlaying != null){
actionPlaying.prevClicked();
}
break;
case ACTION_FORWARD:
if(actionPlaying != null){
actionPlaying.forwardClicked();
}
break;
case ACTION_REWIND:
if(actionPlaying != null){
actionPlaying.rewindClicked();
}
break;
case ACTION_CONTINUE:
Toast.makeText(this, "continue", Toast.LENGTH_SHORT).show();
action.continueMediaPlayer();
}
}
return START_STICKY;
}
public void setCallBack(ActionPlaying actionPlaying){
this.actionPlaying = actionPlaying;
}
public void setCallBack(Action action) {
this.action = action;
}
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
notificationManager.cancelAll();
saveData();
simpleExoPlayer.release();
}
}
and this is my media player initialization :
public void prepareMedia() {
isPlaying=true;
simpleExoPlayer = new SimpleExoPlayer.Builder(MediaPlayer_Activity.this).build();
MediaItem mediaItem = MediaItem.fromUri(audioUrl);
simpleExoPlayer.addMediaItem(mediaItem);
simpleExoPlayer.prepare();
simpleExoPlayer.seekTo(songPrevPosition);
}
Please tell me what's wrong LogCat is not showing anything I don't know how to stop this and where the problem is....
please help

After 9 Android version we have protections for simple service. Simple service can live 10 seconds, no more. You need to declare you service as Foreground Service. It will look like notification in status bar.
For fully information read documentation

according to Android Developers documentation :
You need to upgrade your background process to foreground inorder to make it live without needing your application to be visible to the user.
in order to change your service to foreground one, your service need to have a notification to inform the user that your music player service is working.
a simple foreground service code might look like this :
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Notification notification = buildStartingNotification();
startForeground(startId, notification);
...
return START_STICKY;
}
private Notification buildStartingNotification() {
int priority =NotificationCompat.PRIORITY_LOW;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
priority = NotificationManager.IMPORTANCE_LOW;
createNotificationChannel(priority);
}
Notification notification =
new Notification.Builder(this,CHANNEL_ID)
.setContentTitle("Your_notification_title")
.setContentText("Your_notification_description ")
.setSmallIcon(R.drawable.icon)
.setPriority(priority)
.build();
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void createNotificationChannel(int priority) {
CharSequence name = getText("Your_Channel_Name");
String description = getString("Your_Channel_Desc");
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, priority);
channel.setDescription(description);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
N.B : if you're using application with (target_api > 26) you need to have also a notification channel which I included its code in createNotificationChannel, where your CHANNEL_ID could be any unique string id you want.
if you're wandering what's the meaning of notification channel ?
a notification channel is a mechanism built for android 8 or later to make the user turn off/on group of notification with same channel at once from setting.
as an example your application might have multiple notification channels (news/games/entertainment...etc), then the user can turn off news &games and leave only entertainment on.

First of all make sure you use foreground service. I suggest to you to start permanent notification like this:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
NotificationChannel channel;
Intent notifyIntent = new Intent(this, SomeActivity.class);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent notifyPendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = showStableMessage(this,
getString(R.string.app_desc),
"Message to user",
R.mipmap.ic_icon,
notifyPendingIntent);
startForeground(NotificationUtil.STABLE_CHANNEL_NOTIFY_ID, notification);
return Service.START_STICKY;
}
private Notification showStableMessage(Context context, String title, String message, int icon, PendingIntent intent) {
NotificationChannel channel;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
channel = new NotificationChannel(STABLE_CHANNEL_ID,
STABLE_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(true);
((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
}
Notification notification = new NotificationCompat.Builder(context, STABLE_CHANNEL_ID)
.setContentTitle(title)
.setContentText(Html.fromHtml(message)).setPriority(PRIORITY_DEFAULT)
.setSmallIcon(icon)
.setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
.setContentIntent(intent)
.setCategory(NotificationCompat.CATEGORY_SERVICE).build();
notification.defaults |= Notification.DEFAULT_VIBRATE;
return notification;
}
Second you have to put this in manifest:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
.....>
<service
android:name=".data.service.MyService"
android:foregroundServiceType="mediaPlayback"
android:enabled="true"/>
</application>

Related

How to update foreground service when app is closed?

I'm continuously updating notifications using the Foreground Service. However, after the user forcibly shuts down the app, the notification disappears, so the notification cannot be continuously updated. Even if the user shuts down the app, I want to update the notification while keeping the data intact before shutting down. How can you implement it?
app code
// start service
Intent intent = new Intent(getReactApplicationContext(), ForegroundService.class);
intent.setAction(Constants.ACTION_FOREGROUND_SERVICE_START);
intent.putExtra(NOTIFICATION_CONFIG, Arguments.toBundle(notificationConfig));
getReactApplicationContext().startService(intent);
// update service
Bundle updateBundle = Arguments.toBundle(notificationConfig);
NotificationHelper mNotificationHelper = NotificationHelper.getInstance(this.reactContext);
Notification updateNotification = mNotificationHelper.buildNotification(this.reactContext, updateBundle);
mNotificationManager.notify(notificationId, updateNotification);
Service code
public class ForegroundService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getAction();
if (action != null) {
if (action.equals(Constants.ACTION_FOREGROUND_SERVICE_START)) {
if (intent.getExtras() != null && intent.getExtras().containsKey(NOTIFICATION_CONFIG)) {
Bundle notificationConfig = intent.getExtras().getBundle(NOTIFICATION_CONFIG);
if (notificationConfig != null && notificationConfig.containsKey("id")) {
Notification notification = NotificationHelper.getInstance(getApplicationContext())
.buildNotification(getApplicationContext(), notificationConfig, NotificationType.FOREGROUND);
if(notificationConfig.getBoolean("ongoing")) {
notification.flags |= Notification.FLAG_ONGOING_EVENT;
notification.flags |= Notification.FLAG_SHOW_LIGHTS;
}
startForeground((int)notificationConfig.getDouble("id"), notification);
}
}
} else if (action.equals(Constants.ACTION_FOREGROUND_SERVICE_STOP)) {
stopSelf();
}
}
return START_NOT_STICKY;
}
}
AndroidManifest
<service android:name="com.example.foregroundservice.ForegroundService" android:exported="false" />

How to know os kill my foreground service android

I made a lock screen app. I want to restart my service when the OS kills the service in Xiaomi Redmi Note 10 Pro (MIUI 12). When the service is killed, onDestroy is not call.
public class LockScreenService extends Service {
SharedPreferences prefs;
private BroadcastReceiver screenStateReceiver;
public static boolean isScreenReceiverRegistered=false;
public IBinder onBind(Intent paramIntent) {
return null;
}
public void onCreate() {
super.onCreate();
prefs = getSharedPreferences("SettingPreference", Context.MODE_PRIVATE);
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.setPriority(999);
screenStateReceiver = new ScreenStateReceiver();
registerReceiver(screenStateReceiver, filter);
isScreenReceiverRegistered = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String channelId = createNotificationChannel(notificationManager);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId);
Notification notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.drawable.icon_notification)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.build();
startForeground(127, notification);
}
}
#RequiresApi(Build.VERSION_CODES.O)
private String createNotificationChannel(NotificationManager notificationManager){
String channelId = "my_service_channelid";
String channelName = "Lock Screen Running";
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
// omitted the LED color
channel.setImportance(NotificationManager.IMPORTANCE_NONE);
channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
notificationManager.createNotificationChannel(channel);
return channelId;
}
#Override
public int onStartCommand(final Intent intent, final int flags,
final int startId) {
return START_STICKY;
}
and on onDestroy() function I restart my service.
Manifests
<service android:name=".LockScreenService"
android:process=":ServiceProcess"
android:enabled="true"
android:exported="false"/>
try this, if you want to get it in onResume()
#Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume: GamePreferences.getPid()--------> " + GamePreferences.getPid());
Log.d(TAG, "onResume: android.os.Process.myPid()--------> " + android.os.Process.myPid());
if (GamePreferences.getPid() != 0) {
if (GamePreferences.getPid() != android.os.Process.myPid()) {
Log.d(TAG, "GamePreferences.getPid() != android.os.Process.myPid(): --------> " + android.os.Process.myPid());
//restart your service in foreground
return;
}
}
}
According to the documentation, there is no guarantee onDestroy will be called. I could not find an explicit mention to what happens when the process is killed, but it seems that you are more likely to be called onStop. So you can try to start your service with an intent from onStop.
Also, there are documented ways to prevent your process to be elected, such as: having a related Activity running or having ongoing callbacks in BroadcastReceiver or Service.
Note well that your process might get killed by the user, and refusing to comply to the user's desire to kill is invasive. Therefore the best solution should be designed around the actual reason why a user would want your process to stay alive.

Android Service stops after some time [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I am using this code as a sample for my project to show a fragment on lock screen but it only works till the main activity is not destroyed (not removed from recents) and sometime only works for sometime and than it stops showing fragment on screen..
How can I run a service for all time ? also does new APIs supports it ..
initialize the service in the manifest and the you have to call the service as below in the start button
Intent i = new Intent(this, AnotherService.class);
i.setAction("C.ACTION_START_SERVICE");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(i);
}
else
{
startService(i);
}
then you have to start the service just like below
public class AnotherService extends Service {
static final int NOTIFICATION_ID = 543;
public AnotherService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
startMyOwnForeground();
else
startForeground(1, new Notification());
//your code here
}
#RequiresApi(Build.VERSION_CODES.O)
private void startMyOwnForeground() {
String NOTIFICATION_CHANNEL_ID = "example.permanence";
String channelName = "Background Service";
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
Notification notification = notificationBuilder.setOngoing(true)
.setContentTitle("App is running in background")
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(2, notification);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
//return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
}
if you done the service then you have to change the stop button code with this in your activity where you want to stop
stopService(new Intent(YourActivity.this, AnotherService.class));

Android Service stops broadcasting progress after a while

I have an Activity where the user can download a video. Upon user's click, the Download Service starts to download the content.
There is a progress bar in the Activity UI which I would like to update according to download progress in the service which broadcasts the progress periodically.
Everything works fine but after a certain time the service stops sending any broadcast progress, hence, the UI does not update anymore.
Additionally, how I can resume receiving the progress broadcast when the user goes to another Activity and comes back to this Activity? I mean, even if the above issue is solved, when the user presses back button and go to other activity and comes back to this activity, the progress gets lots. How can I check for any existing broadcast and receive it whenever the user comes to this activity.
In the ACTIVITY:
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Log.d("DownloadService", "Progress Received In Activity");
Double progress = bundle.getDouble("PROGRESS");
updateDownloadProgressBar(progress);
}
}
};
private void startDownloadService() {
final String videoId = mItem.getAttributes().get(KEY_ASSET_ID);
Intent intent = new Intent(this, DownloadService.class);
intent.putExtra("VIDEOID", videoId);
startService(intent);
}
in the onResume():
registerReceiver(receiver, new IntentFilter(DownloadService.NOTIFICATION_SERVICE));
in the onPause():
unregisterReceiver(receiver);
In the SERVICE:
private void publishProgress(double progress) {
Log.d(TAG, "Broadcasting progress from Service");
Intent intent = new Intent(NOTIFICATION_SERVICE);
intent.putExtra("PROGRESS", progress);
sendBroadcast(intent);
}
The download and progress work fine to 38% then stop.
It seems that the service is being stopped/killed from the OS, to avoid that use foreground service so you can make sure it will not be killed from the OS.
See the sample code below:
Service
public class PendingService extends Service {
private final static String TAG = "PendingService";
public final static int NOTIFICATION_ID = 94;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startInForeground();
// Do your work here ...
return START_STICKY;
}
private void startInForeground() {
String NOTIFICATION_CHANNEL_ID = "default";
String NOTIFICATION_CHANNEL_NAME = "My Pending Service";
String NOTIFICATION_CHANNEL_DESC = "This notification holding a pending task";
Intent notificationIntent = new Intent(this, SplashActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.notification)
.setOngoing(true)
.setAutoCancel(true)
.setContentIntent(pendingIntent);
if (Build.VERSION.SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
channel.setDescription(NOTIFICATION_CHANNEL_DESC);
channel.setSound(null, null);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
}
Notification notification = builder.build();
startForeground(NOTIFICATION_ID, notification);
}
#Override
public void onDestroy() {
super.onDestroy();
removeNotification(NOTIFICATION_ID);
// ....
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void removeNotification(int notificationId) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.cancel(notificationId);
}
}
}
Utils you may need
class ServiceUtils {
/**
* #param service: Service to run
*/
fun startService(context: Context, service: Class<out Service>) {
val serviceIntent = Intent(context, service)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(serviceIntent)
} else {
context.startService(serviceIntent)
}
}
/**
* #return True: if the service is running
*/
fun isServiceRunning(context: Context, serviceClass: Class<*>): Boolean {
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.name == service.service.className) {
return true
}
}
return false
}
}

Run API every second in Background after Android App is killed in Oreo version

I am trying to Build a Android Application which will run every second and when app is closed or killed then also it should run continuously in Background.
When API response condition is satisfied it should show a Local Notification..
I have used Service Class for background Task. It was working fine in all version Except the Oreo Version (8.1v)
I have check website and Example related to it, I have find out that we can't perform background task in Oreo Version after the app is closed or killed.
So I tried to use startForeground() then also it is not working,
After many tries, finally I am asking this question here.
So please help me to run a API in Background when App is closed.
MainActivty.class
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(this, new Intent(this,MyService.class));
} else {
startService(new Intent(this,MyService.class));
}
}
MyService.class
public class MyService extends Service {
public static final int notify = 3000; //interval between two services(Here Service run every 5 Minute)
private Handler mHandler = new Handler(); //run on another Thread to avoid crash
private Timer mTimer = null; //timer handling
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
if (mTimer != null) // Cancel if already existed
mTimer.cancel();
else
mTimer = new Timer(); //recreate new
mTimer.scheduleAtFixedRate(new TimeDisplay(), 0, notify); //Schedule task
}
//class TimeDisplay for handling task
class TimeDisplay extends TimerTask {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
new ApiCallAsyncTask().execute(URL);
}
});
}
}
}
Notification Method which is called in ApiCallAsyncTask class
Notification notif;
#TargetApi(Build.VERSION_CODES.O)
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void notification(String Name, String time,String mId,int id){
Intent intent = new Intent(MyService.this, MainActivity.class);
String CHANNEL_ID = String.valueOf(id);
PendingIntent pendingIntent = PendingIntent.getActivity(MyService.this, 100, intent, PendingIntent.FLAG_ONE_SHOT);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, Name, NotificationManager.IMPORTANCE_DEFAULT);
notif = new Notification.Builder(MyService.this)
.setContentIntent(pendingIntent)
.setContentTitle("Reminder")
.setContentText("hello")
.setSmallIcon(R.drawable.logo)
.setOnlyAlertOnce(true)
.setColor(ContextCompat.getColor(MyService.this, R.color.colorPrimaryDark))
.setChannelId(CHANNEL_ID)
.build();
notificationManager.createNotificationChannel(mChannel);
}else {
notif = new Notification.Builder(MyService.this)
.setContentIntent(pendingIntent)
.setContentTitle("Reminder")
.setContentText("hello")
.setSmallIcon(R.drawable.logo)
.setOnlyAlertOnce(true)
.setColor(ContextCompat.getColor(MyService.this, R.color.colorPrimaryDark))
.build();
}
notif.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(id, notif);
startForeground(1, notif);
}
Thank You..
You can use combination of JobIntentService + AlarmManager(for scheduling) or JobScheduler API.
But I strongly recommend replace your approach with Firebase Cloud Messaging. So you will place business logic on server side and notify clients in special cases.

Categories