I'm creating a service that runs a mediaplayer for a set period of time.This service gets a constant value that I defined in another class and based on that the duration of the playing is determined.
I looked all over the web but couldn't find a solution or a similar problem , spent hours trying to no avail
package com.quantyam.sleepbaby.sleepbaby;
import android.app.IntentService;
import android.app.Service;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.widget.Toast;
public class ContinousService extends IntentService {
private static final String TAG = "HelloService";
MediaPlayer player;
private boolean isRunning = false;
int time = 0;
Thread runner;
boolean keepplaying=true;
Handler mHandler = new Handler();
boolean keepgoiong = true;
public ContinousService() {
super("ContinousPlayer");
}
private void sendMessageToActivity(int msg) {
Intent intent = new Intent("intentKey");
intent.putExtra("current_timing", msg);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
#Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
isRunning = true;
}
public static String
ACTION_CONTINOUS_PLAY = "";
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("******************************************* selected DUration = " + Constant.PlayDuration);
Log.i(TAG, "Service onStartCommand");
//Creating new thread for my service
//Always write your long running tasks in a separate thread, to avoid ANR
new Thread(new Runnable() {
#Override
public void run() {
runner = Thread.currentThread();
//Your logic that service will perform will be placed here
//In this example we are just looping and waits for 1000 milliseconds in each loop.
while (keepgoiong) {
try {
Thread.sleep(1000);
startplaying();
time++;
} catch (Exception e) {
e.printStackTrace();
}
if (isRunning) {
Log.i(TAG, "Service running and time is = " + time);
}
}
//Stop service once it finishes its task
stopSelf();
}
}).start();
return Service.START_STICKY;
}
public void startplaying() {
try {
if(keepplaying) {
if (player == null) {
AssetFileDescriptor afd = getAssets().openFd("music/" + Constant.SelectedMusic);
player = new MediaPlayer();
player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
player.prepare();
player.start();
System.out.println("============================= player Started!");
}
final int duration = Integer.parseInt(Constant.PlayDuration) * 15;
int timeleft = duration - time;
sendMessageToActivity(timeleft);
System.out.println("============================= time left = " + timeleft);
if (player.isPlaying() && timeleft > 0) {
} else if (!player.isPlaying() && timeleft > 0) {
System.out.println("================================== Run Again!");
// player.prepare();
player.start();
} else if (player.isPlaying() && timeleft <= 0) {
System.out.println("============================= Time is up!");
player.stop();
keepplaying=false;
keepgoiong = false;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public IBinder onBind(Intent arg0) {
Log.i(TAG, "Service onBind");
return null;
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
}
Handler handler = new Handler();
#Override
public void onDestroy() {
keepgoiong = false;
isRunning=false;
keepplaying=false;
player.stop();
super.onDestroy();
// stopSelf();
Log.i(TAG, "Service onDestroy");
}
}
when the time is up I call stopSelf() but everytime I get the following error message :
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.quantyam.sleepbaby.sleepbaby, PID: 6550
java.lang.RuntimeException: Unable to stop service com.quantyam.sleepbaby.sleepbaby.ContinousService#cbde8b0: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.Looper.quit()' on a null object reference
at android.app.ActivityThread.handleStopService(ActivityThread.java:3732)
at android.app.ActivityThread.-wrap30(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1745)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.Looper.quit()' on a null object reference
at android.app.IntentService.onDestroy(IntentService.java:138)
at com.quantyam.sleepbaby.sleepbaby.ContinousService.onDestroy(ContinousService.java:153)
at android.app.ActivityThread.handleStopService(ActivityThread.java:3715)
at android.app.ActivityThread.-wrap30(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1745)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
my code https://codeshare.io/5MJEVQ
An IntentService runs on its own thread.
So what you are doing is starting a thread that starts another thread that starts the media player and waits before calling stopSelf() on the first thread.
An intent service is only available for as long as it has work.
If the intent service launches another thread... its work is done and it will go away.
When you call the stopSelf() method your Intent service has already gone away because it started the thread and has completed its work...
I would first suggest that when the intent service starts you start the media player. Then use a PostDelayed runnable to stop the media player when it is finished. Something like below. Note: that this will still not work as is because the IntentService will finish its work once it starts the postDelayed Runnable. Solution is to use a Service instead of an IntentService.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("******************************************* selected DUration = " + Constant.PlayDuration);
Log.i(TAG, "Service onStartCommand");
startMediaPlayer();
new Handler().postDelayed(new Runnable() {
public void run () {
stopSelf();
}
}, playDuration);
return Service.START_STICKY;
}
I would suggest that you use a Service instead of an IntentService.
Here is an example of a media player in a service. It uses state and intents to receive actions from UI and Uses Broadcast receivers to update ui when needed.
Related
I'm working on an application that which is media player.
Question: How do I make media player (application) work without issues from turning the screen off?
Question: loadInBackground() returns the uri but onLoadFinished not called when screen off.
Few words to explain trouble better:
The media player contains Loader which loads the song and another Loader which loads related suggestions. I've also implemented the method to play_next() which relies on a listener of media player on finished (button in right upper corner).
The media player is initialized in the service class which I've made so the user can search new songs, and prepare the next_song() with the button (and the playing continues because I connect to service each time Activity is loaded and I return from service media player so I can attach listener for onFinish method).
The thing that bothers me is that when the user turns off the screen, the activity goes to idle state (status from android monitor - log cat) and once in idle state (aka turned off screen) if the song ends, it will start new intent which is media player to start initializing and auto-playing song. It works when the screen is on but it doesn't if it goes to idle state.
If I turn on the screen I get activity to act like this:
Little pink dot is a progress bar. So the activity tries to refresh itself?
In the onCreate() method I call start_loader which initializes and does the things with Loader.
I've seen some power manager tools and seen the bad comments about it which imply to the battery usage but I did try it and from log cat it just went to idle state again (if it matters).
Help please, maybe if I override onPause() Activity and onResume()?
Also i get message from loadInBackground() which is uri from song and from there on it freezes doesn't continue.
you need to create Service for that that run on Background.so when you play song don'tstop if you keep you screen off.Service in Android
upper link perfectly describe service.
example of service ...
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.RequiresApi;
import android.util.Log;
import android.widget.Toast;
import com.example.divyesh.musiclite.Pojos.SongsList;
import java.io.File;
import java.io.IOException;
/**
* Created by Divyesh on 11/18/2017.
*/
public class MediaSongServiece extends Service {
SongsList s;
private static Boolean destroy = false;
private String TAG = "HELLO";
private MusicIntentReceiver reciever;
private SharedPreferences prefrence;
private static MediaPlayer player;
private int thisStartId = 1;
private String ss[];
SharedPreferences.Editor editor;
public IBinder onBind(Intent arg0) {
return null;
}
public static void requestPlayMedia() {
player.start();
}
public void requestPauseMedia() {
player.pause();
}
#Override
public void onCreate() {
super.onCreate();
reciever = new MusicIntentReceiver();
IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
registerReceiver(reciever, filter);
Log.d("service", "onCreate");
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
stopSelf();
}
#Override
public boolean onUnbind(Intent intent) {
stopSelf(thisStartId);
return super.onUnbind(intent);
}
public void onStart(Intent intent, int startId) {
if (intent.equals(null)) {
stopSelf();
}
if (destroy == false) {
thisStartId = startId;
ss = intent.getExtras().getStringArray("getArray");
Log.e(TAG, "onStart: " + ss[0] + ss[1] + " path" + ss[5]);
s = new SongsList();
s.setAll(ss);
if (player != null) {
player.stop();
player.reset();
try {
player.setDataSource(getApplicationContext(), Uri.fromFile(new File(s.getPath())));
player.prepare();
} catch (IOException e) {
e.printStackTrace();
}
player.setLooping(true);
player.setVolume(100, 100);
player.start();
Log.e(TAG, "onStart: m= is not null" + player.isPlaying());
} else {
player = MediaPlayer.create(getApplicationContext(), Uri.fromFile(new File(s.getPath())));
player.setLooping(true);
player.setVolume(100, 100);
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
Log.e(TAG, "onStart: m= is null WE created new player");
}
} else {
Log.e(TAG, "onelse destroy ");
recover();
}
}
private void recover() {
destroy = false;
prefrence = getSharedPreferences("SongPrefrence", Context.MODE_PRIVATE);
for (int i = 0; i <= 5; i++) {
ss[i] = prefrence.getString("" + i, "");
}
String currentPose = prefrence.getString("current_pos", "");
Log.e(TAG, "recover: Shared Daata is" + ss[5] + "_______" + currentPose);
}
#Override
public void onDestroy() {
unregisterReceiver(reciever);
player.stop();
player.release();
stopSelf(thisStartId);
}
#Override
public void onLowMemory() {
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
prefrence = getSharedPreferences("SongPrefrence", Context.MODE_PRIVATE);
editor = prefrence.edit();
destroy = true;
}
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
prefrence = getSharedPreferences("SongPrefrence", Context.MODE_PRIVATE);
editor = prefrence.edit();
destroy = true;
}
}
#RequiresApi(api = Build.VERSION_CODES.M)
private void saveData() {
player.pause();
for (int i = 0; i < ss.length; i++) {
editor.putString("" + i, ss[i]);
}
editor.putString("current_pos", "" + player.getCurrentPosition());
editor.commit();
}
public class MusicIntentReceiver extends BroadcastReceiver {
public String TAG = "ss";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
int state = intent.getIntExtra("state", -1);
switch (state) {
case 0:
Log.d(TAG, "Headset is unplugged");
Toast.makeText(context, " Headset is unpluged ", Toast.LENGTH_SHORT).show();
Log.e(TAG, "onReceive: " + " is play song " + player.isPlaying());
break;
case 1:
Log.d(TAG, "Headset is plugged");
break;
default:
Log.d(TAG, "I have no idea what the headset state is");
}
}
}
}
}
In my application I want use service for get request to server.
I should run this service for always and not stop it!
I write below code in service, but just show for 5 time and when receive to 5 step. then not show Toast!
But I want always getData() and show Toast.
Service class :
public class NotifyService extends Service {
private static final String TAG = "HelloService";
private boolean isRunning = false;
#Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
isRunning = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand");
//Creating new thread for my service
//Always write your long running tasks in a separate thread, to avoid ANR
new Thread(new Runnable() {
#Override
public void run() {
//Your logic that service will perform will be placed here
//In this example we are just looping and waits for 5000 milliseconds in each loop.
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(5000);
} catch (Exception e) {
}
if (isRunning) {
ExploreSendData sendData = new ExploreSendData();
sendData.setPageIndex(1);
sendData.setPageSize(10);
sendData.setShowFollows(false);
sendData.setShowMovies(true);
sendData.setShowNews(true);
sendData.setShowReplies(false);
sendData.setShowSeries(true);
sendData.setShowSuggestions(false);
InterfaceApi api = ApiClient.getClient().create(InterfaceApi.class);
Call<ExploreResponse> call = api.getExplore(new SharedPrefrencesHandler(NotifyService.this)
.getFromShared(SharedPrefrencesKeys.TOKEN.name()), sendData);
call.enqueue(new Callback<ExploreResponse>() {
#Override
public void onResponse(Call<ExploreResponse> call, Response<ExploreResponse> response) {
if (response.body().getData() != null && response.body().getStatusCode() != 401
&& response.body().getStatusCode() != 402) {
Toast.makeText(NotifyService.this, "Test Show message ever 5second", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ExploreResponse> call, Throwable t) {
}
});
}
}
//Stop service once it finishes its task
stopSelf();
}
}).start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
Log.i(TAG, "Service onBind");
return null;
}
#Override
public void onDestroy() {
isRunning = false;
Log.i(TAG, "Service onDestroy");
}
}
I copy this service code from internet, but just show 5times. I want show always.
How can I edit my codes and fix it? Please help me. Thanks
The problem is not in the service, services start and continue living as long as the app is alive and android doesn't kill it. For an infinite loop replace the "for loop" with "While loop". The below loop doesn't end.
while (true) {
......
......
......
}
I am working on below code to run a service in background,but the problem is i am not getting how to run the service indefinitely even though the app is closed,here on press of back my service is stopping.I have read many tutorials but still confused with this.
public class HelloService extends Service {
private static final String TAG = "HelloService";
private boolean isRunning = false;
#Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
isRunning = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand");
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
if (isRunning) {
Log.i(TAG, "Service running");
}
}
//Stop service once it finishes its task
stopSelf();
}
}).start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
Log.i(TAG, "Service onBind");
return null;
}
#Override
public void onDestroy() {
isRunning = false;
Log.i(TAG, "Service onDestroy");
}
}
On Android there is NO way (at least for a third party app) to have a never ending process running. The system can always kill your service. So you can use a foreground service but the system can kill your service even in this case (even with low probability). In addition, you should consider that the cpu can go to sleep. So you should take a wakelock but in this way you can kill the user battery so it's not a good solution. My suggestion is to always work "on event" for example with a brodacast receiver that starts a intent service, it does some work and then exit. The always running processes are simply a wrong design choices on Android.
One Way is to use while loop but keep a check i.e
while(true) {
if (condition != true) {
Thread.sleep(time);
} else {
break;
}
}
These methods are implemented in a class extending Service. A new service is started every time a button is pressed.
If the button is pressed once, LogCat outputs what I expect, which includes a final output of "Service onDestroy." However, when the button is pressed twice, the second time before the first service ended, "Service onDestroy." displays only once when the first service is done, and the second service prints out the rest of "Service Running" logs but not "Service onDestroy."
Can anyone tell me why? Thank you!
public int onStartCommand(Intent intent,int flags, int startId) {
Log.i(TAG,"Service onStartCommand " + startId);
final int currentId = startId;
Runnable r = new Runnable() {
public void run() {
for (int i = 0; i < 3; i++) {
long endTime = System.currentTimeMillis() + 10*1000;
while (System.currentTimeMillis() < endTime) {
synchronized(this) {
try {
wait(endTime - System.currentTimeMillis());
}catch (Exception e) {
}
}
}
Log.i(TAG,"Service running");
}
stopSelf();
}
};
Thread t = new Thread(r);
t.start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.i(TAG,"Service onBind");
return null;
}
#Override
public void onDestroy() {
Log.i(TAG,"Service onDestroy");
}
In the guide for Services they use don't use stopSelf() but stopSelf(startId) when extending Service. The first stopSelf() propably stops both executions of your Service.
See here: http://developer.android.com/guide/components/services.html
Edit: Also a service is only created and destroyed once even when there are several executions of it running it is still a single service. In your case (a Bound Service) it will only be destroyed when the last excecution finishes. For logging every excecution ending you could try to override the stopSelf(int startId) method.
Can anyone tell me the way to keep a Service always running or restarting itself when the user close it? I've watched that facebook services restart when i clear memory.
I don't want to make ForegroundServices.
You should create a sticky service. Read more about it here.
You can do this by returning START_STICKY in onStartCommand.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
Read also about application:persistent which is "Whether or not the application should remain running at all times". This is more troublesome - System will try not to kill your app which will effect others in the system, you should be careful using it.
I copied this from a service I used in an app I did before.
ITS IMPORTANT TO NOT UPDATE ANY UI. because you have no user interface in services. this applies to Toasts as well.
good luck
public class nasserservice extends Service {
private static long UPDATE_INTERVAL = 1*5*1000; //default
private static Timer timer = new Timer();
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate(){
super.onCreate();
_startService();
}
private void _startService()
{
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
doServiceWork();
}
}, 1000,UPDATE_INTERVAL);
Log.i(getClass().getSimpleName(), "FileScannerService Timer started....");
}
private void doServiceWork()
{
//do something wotever you want
//like reading file or getting data from network
try {
}
catch (Exception e) {
}
}
private void _shutdownService()
{
if (timer != null) timer.cancel();
Log.i(getClass().getSimpleName(), "Timer stopped...");
}
#Override
public void onDestroy()
{
super.onDestroy();
_shutdownService();
// if (MAIN_ACTIVITY != null) Log.d(getClass().getSimpleName(), "FileScannerService stopped");
}
}