I need to have background music in all my activities. It should stop when the application is not foreground. As I'm developing for 2.3 I can't use the ActivityLifeCycleCallBacks class. I implemented the solution at Checking if an Android application is running in the background and then decided to make the mediaplayer a singleton and use it in a service.
Everything works fine and if I press home, select quit from the menu or I make the application go background any way the sound stops but... after some random time when I'm doing something else or even when the screen is turned off the music will start again out of the blue. Even if I kill the application from task manager the will start again later again.
This is my first singleton and my first time playing with service so I guess I'm missing something really basic. I think I'm closing the service but apparently I'm not.
Here is the code:
PlayAudio.java
import ...
public class PlayAudio extends Service{
private static final Intent Intent = null;
MediaPlayer objPlayer;
private int length = 0;
boolean mIsPlayerRelease = true;
private static PlayAudio uniqueIstance; //the singleton
static PlayAudio mService;
static boolean mBound = false; // boolean to check if the service containing this singleton is binded to some activity
public static boolean activityVisible; // boolean to check if the activity using the player is foreground or not
//My attempt to make a singleton
public static PlayAudio getUniqueIstance(){
if (uniqueIstance == null) {
uniqueIstance = new PlayAudio();
}
return uniqueIstance;
}
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
static public ServiceConnection mConnection = new ServiceConnection() {// helper for the activity
public void onServiceConnected(ComponentName className,
IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
public static Intent createIntent (Context context) { //helper for the activity using the player
Intent intent = new Intent(context, PlayAudio.class);
return intent;
}
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
PlayAudio getService() {
// Return this instance so clients can call public methods
return PlayAudio.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public void onCreate(){
super.onCreate();
Log.d(LOGCAT, "Service Started!");
objPlayer = MediaPlayer.create(this,R.raw.kickstarterreduced);
objPlayer.setLooping(true);
mIsPlayerRelease = false;
}
public int onStartCommand(Intent intent, int flags, int startId){
objPlayer.start();
Log.d(LOGCAT, "Media Player started!");
if(objPlayer.isLooping() != true){
Log.d(LOGCAT, "Problem in Playing Audio");
}
return 1;
}
public void onStop(){
objPlayer.setLooping(false);
objPlayer.stop();
objPlayer.release();
mIsPlayerRelease = true;
}
public void onPause(){
if(objPlayer.isPlaying())
{
objPlayer.pause();
length=objPlayer.getCurrentPosition(); // save the position in order to be able to resume from here
}
}
public void resumeMusic() // if length is 0 the player just start from zero
{ if (mIsPlayerRelease == true) {
objPlayer = MediaPlayer.create(this,R.raw.kickstarterreduced);
mIsPlayerRelease = false;
}
if(objPlayer.isPlaying()==false )
{
if (length != 0) objPlayer.seekTo(length);
objPlayer.start();
}
}
}
And this are the methods I have implemented in every activity's class
SharedPreferences sharedPrefs;
PlayAudio playerIstanced;
public static boolean activityVisible;
#Override
public void onStart() {
super.onStart();
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
}
#Override
public void onResume() {
super.onResume();
playerIstanced= PlayAudio.getUniqueIstance(); //call singleton
bindService(PlayAudio.createIntent(this), playerIstanced.mConnection, Context.BIND_AUTO_CREATE); // create the service
if (sharedPrefs.getBoolean("sound", true) == true) {// if sound is enabled in option it will start the service
startService(PlayAudio.createIntent(this));
playerIstanced.mService.activityResumed();
if (playerIstanced.mBound == true) {
playerIstanced.mService.resumeMusic();
}
}
}
#Override
public void onPause() {
super.onPause();
playerIstanced.mService.activityPaused();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
//If the phone lags when changing activity (between onPause() and the other activity onResume() the music won't stop. If after 500ms onResume() is not called it means the activity went background...Am I messing with service here?
if (playerIstanced.mService.isActivityVisible() != true) {
playerIstanced.mService.onPause();
}
}
}, 500);
}
#Override
public void onStop(){
super.onStop();
// Unbind from the service
if (playerIstanced.mService.mBound) {
playerIstanced.mService.mBound = false;
unbindService(playerIstanced.mService.mConnection);
}
}
}
Stop music automatically when user exit from app
This part has to be in EVERY activity's onPause:
public void onPause(){
super.onPause();
Context context = getApplicationContext();
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> taskInfo = am.getRunningTasks(1);
if (!taskInfo.isEmpty()) {
ComponentName topActivity = taskInfo.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
StopPlayer();
Toast.makeText(xYourClassNamex.this, "YOU LEFT YOUR APP. MUSIC STOP", Toast.LENGTH_SHORT).show();
}
}
}
This part has to be in EVERY activity's onResume:
Play music automatically when user resume the app
Public void onResume()
{
super.onResume();
StartPlayer();
}
Hope it helps!!
You can check my answer according to this topic may it will sove your issue.
You need to manually stop the service using Context.stopService() or stopSelf(). See the Service Lifecycle section of http://developer.android.com/reference/android/app/Service.html.
Service Lifecycle
There are two reasons that a service can be run by the system. If someone calls Context.startService() then the system will retrieve the service (creating it and calling its onCreate() method if needed) and then call its onStartCommand(Intent, int, int) method with the arguments supplied by the client. The service will at this point continue running until Context.stopService() or stopSelf() is called. Note that multiple calls to Context.startService() do not nest (though they do result in multiple corresponding calls to onStartCommand()), so no matter how many times it is started a service will be stopped once Context.stopService() or stopSelf() is called; however, services can use their stopSelf(int) method to ensure the service is not stopped until started intents have been processed.
I believe you can simply put playerIstanced.stopSelf() in the onStop() call of each activity.
My understanding is that the service continues to run quietly after your application stops. After a while the system kills the service to free up resources, and then after a while more when resources are available it restarts the service. When the service restarts its onResume() is called and the music begins playing.
it helped me stop the mediaplayer.
Use Handler(getMainLooper()) to start and stop MediaPlayer.
final Handler handler = new Handler(getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
mediaPlayer.start();
}
});
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
}
, 30 * 1000);
Related
I'm developing an application, which plays music in the background by using service.
Music stops when we hit back app will be paused and but, music is not resuming when I get back to the application.
public class backService extends Service implements ComponentCallbacks2 {
private MediaPlayer mp;
SharedPreferences sharedpreferences;
public Boolean musicSwitch;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
if (mp != null){
mp.stop();
mp.release();
}
}
#Override
public void onCreate() {
super.onCreate();
sharedpreferences = getSharedPreferences(mypreference,
Context.MODE_PRIVATE);
musicSwitch = sharedpreferences.getBoolean("music", true);
if(musicSwitch){
mp = MediaPlayer.create(this, R.raw.all);
mp.setLooping(true);
mp.start();
}
}
#Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
if(mp != null){
mp.pause();
}
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I want the application to resume music when we get back to the application, I have tried using onResume method, but there is no onResume method in services.
TIA
1) You need to create foreground service to prevent it from killing by OS
How can we prevent a Service from being killed by OS?
2) You can bind service (bindService(serviceIntent)) and use Binder interface
https://developer.android.com/guide/components/bound-services.html#Binder
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
Activity:
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
unbindService(mConnection);
mBound = false;
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
}
}
3) Then, in your activity onResume you can call method from your Binder to control music
Hi in project I'm using service for chat communication using SignalR. Chat communication is working fine but when the app goes to background the service got stopped I need to run the services fully till my app get deleted
Here is me service code
public class SignalRService extends Service {
private HubConnection mHubConnection;
private HubProxy mHubProxy;
private Handler mHandler; // to display Toast message
private final IBinder mBinder = new LocalBinder(); // Binder given to clients
public SignalRService() {
}
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler(Looper.getMainLooper());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
int result = super.onStartCommand(intent, flags, startId);
startSignalR();
return result;
}
#Override
public void onDestroy() {
Log.i("onDestroy","onDestroy");
mHubConnection.stop();
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
// Return the communication channel to the service.
startSignalR();
return mBinder;
}
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
public SignalRService getService() {
// Return this instance of SignalRService so clients can call public methods
return SignalRService.this;
}
}
/**
* method for clients (activities)
*/
public void sendMessage(String message) {
String SERVER_METHOD_SEND = "Send";
mHubProxy.invoke(SERVER_METHOD_SEND, message);
}
/**
* method for clients (activities)
*/
public void sendMessage_To(String receiverName, String message) {
String SERVER_METHOD_SEND_TO = "SendChatMessage";
mHubProxy.invoke(SERVER_METHOD_SEND_TO, receiverName, message);
}
private void startSignalR() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
Credentials credentials = new Credentials() {
#Override
public void prepareRequest(Request request) {
request.addHeader("User-Name", "BNK");
}
};
String serverUrl = "http://10.10.10.180/signalr/hubs";
mHubConnection = new HubConnection(serverUrl);
mHubConnection.setCredentials(credentials);
String SERVER_HUB_CHAT = "ChatHub";
mHubProxy = mHubConnection.createHubProxy(SERVER_HUB_CHAT);
ClientTransport clientTransport = new ServerSentEventsTransport(mHubConnection.getLogger());
SignalRFuture<Void> signalRFuture = mHubConnection.start(clientTransport);
try {
signalRFuture.get();
} catch (InterruptedException | ExecutionException e) {
Log.e("SimpleSignalR", e.toString());
return;
}
sendMessage("Hello from BNK!");
String CLIENT_METHOD_BROADAST_MESSAGE = "broadcastMessage";
mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE,
new SubscriptionHandler1<CustomMessage>() {
#Override
public void run(final CustomMessage msg) {
final String finalMsg = msg.UserName + " says " + msg.Message;
// display Toast message
mHandler.post(new Runnable() {
#Override
public void run() {
Log.i("message","message: "+finalMsg);
Toast.makeText(getApplicationContext(), finalMsg, Toast.LENGTH_SHORT).show();
}
});
}
}
, CustomMessage.class);
}}
And here is the activity code
public class MainActivity extends AppCompatActivity {
private final Context mContext = this;
private SignalRService mService;
private boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setClass(mContext, SignalRService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
// Unbind from the service
Log.i("onStop","onStop");
if (mBound) {
unbindService(mConnection);
mBound = false;
}
super.onStop();
}
public void sendMessage(View view) {
if (mBound) {
// Call a method from the SignalRService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
EditText editText = (EditText) findViewById(R.id.edit_message);
EditText editText_Receiver = (EditText) findViewById(R.id.edit_receiver);
if (editText != null && editText.getText().length() > 0) {
String receiver = editText_Receiver.getText().toString();
String message = editText.getText().toString();
mService.sendMessage_To(receiver, message);
mService.sendMessage(message);
}
}
}
/**
* Defines callbacks for service binding, passed to bindService()
*/
private final ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to SignalRService, cast the IBinder and get SignalRService instance
SignalRService.LocalBinder binder = (SignalRService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Log.i("onServiceDisconnected","onServiceDisconnected");
mBound = false;
}
};}
My manifest code for service
<service
android:name=".SignalRService"
android:enabled="true"
android:exported="true" >
</service>
Plese help me on this
If you bind the service with any component the system will automatically destroy the service if no other client is bound with it.
If you want to run a service independently then you have to start a service rather than bind. But you can't communicate with a service if you start it with startService()
For more details you can see the documentation here
You can BOTH start AND bind the service.
In this way, even if multiple components bind to the service at once, then ALL of them unbind, the service will NOT be destroyed. Refer to A service can essentially take two forms: Bound
your service can work both ways: it can be started (to run indefinitely) and also allow binding. It's simply a matter of whether you implement a couple callback methods: onStartCommand() to allow components to start it and onBind() to allow binding.
// onBind method just return the IBinder, to allow clients to get service.
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// onStartCommand just return START_STICKY to let system to
// try to re-create the service if the servcie's process is killed.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
// and make startSignalR public to allow client to call this method.
public void startSignalR() {
}
In your clients, no need to keep a boolean mBound.
Just bind service when onCreate, unbind service when onDestroy. DO NOT unbind when onStop. Since onStop may called many times, for example dialog popup will invoke onStop, but your activity is still on foreground, this will cause your service destroyed.
Refer to my answer for question: Pass Service From one Activity to Another for sample code.
I'm trying to add background music to my game and I thought I could persist it across activities by starting the service and then just connecting and binding to it in different activities in order to control it. But my music stops playing when I try to establish a connection from my second activity. I'm very new to working with services, so I apologize for any simple mistakes.
From my MusicService class (extends Service)
private final IBinder mBinder = new ServiceBinder();
MediaPlayer mPlayer;
private int length = 0;
public static boolean STOP_ON_DESTROY = true;
// Binder subclass. Allows access from clients to the server
public class ServiceBinder extends Binder {
MusicService getService(){
return MusicService.this;
}
}
public MusicService() {}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate(){
super.onCreate();
}
#Override
public int onStartCommand (Intent intent, int flags, int startId)
{
return START_STICKY;
}
public boolean isPlaying(){
if(mPlayer != null){
return mPlayer.isPlaying();
}
return false;
}
public void stopMusic()
{
if(mPlayer != null){
if(mPlayer.isPlaying()) {
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
System.out.println("stopMusic service fn");
}
}
This is the code I call in both my Main and secondary activities in order to interact with the service. The music stops during the connectToMusicService function in the secondary activity. The Main activity works great.
onCreate(){....
startMusicService();
MusicService.STOP_ON_DESTROY = true;
}
private void startMusicService() {
Intent musicIntent = new Intent();
musicIntent.setClass(getApplicationContext(), MusicService.class);
startService(musicIntent);
}
#Override
public void onStart(){
super.onStart();
// establish connection for binding to the service
connectToMusicService();
// bind to the service
bindToMusicService();
}
private void bindToMusicService() {
Intent intent = new Intent(this, MusicService.class);
bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE);
MusicService.STOP_ON_DESTROY = true;
}
private void connectToMusicService() {
myServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.ServiceBinder binder = (MusicService.ServiceBinder) service;
mService = binder.getService();
if(!mService.isPlaying())
mService.startMusic();
isServiceBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("Service disconnected from main");
isServiceBound = false;
}
};
}
The only thing I do during my Main activity's onStop is
#Override
public void onStop(){
super.onStop();
if(mService != null) {
if (MusicService.STOP_ON_DESTROY) {
mService.stopMusic();
}
}
}
UPDATE: I got it working. My issue wasn't with service binding at all. It was with static STOP_ON_DESTROY variable I was using to manage whether the music should stop when leaving an activity. I cleaned that up and all is good now. Thanks!
First of all, do you need to bind at all? Or could starting the service be enough? Started services run until you stop them (except if killed by the system when resources are scarce). I am not sure there's any point binding from each of your activities.
Btw if your service should run and play music also when your activities are closed, consider making it a foreground service.
I'm working on my first Android app and I have a problem with services. I have one activity and one service, in the activity there is a button which calls a method in the service and in the service I have one timer which after 20 seconds shows something in Logcat. In the activity I start the service with startService(intet) and then bind to it in order to keep it working even after closing the activity as it was suggested in many topics.
If I hit the back button or home button the app works properly, but if I hold the home button and then close the app I do not see the log, but if I go to app manager under the Running tab I can see my app and the service is running!
I do not want to use alarm manager. There reason that I am using a timer here is that I want to make sure my service is really working! I just want to do something in the service and make sure it will work even if the app is closed.
public class BoundService extends Service {
private final IBinder myBinder = new MyLocalBinder();
#Override
public IBinder onBind(Intent intent) {
return myBinder;
}
public int onStartCommand(Intent intent, int flags, int startId)
{
return START_STICKY;
}
#Override
public void onDestroy()
{
super.onDestroy();
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
}
public void testNotification()
{
int interval = 20000; // 20 Second
Handler handler = new Handler();
Runnable runnable = new Runnable(){
public void run() {
Log.d("BoundService", "Timer");
}
};
handler.postAtTime(runnable, System.currentTimeMillis()+interval);
handler.postDelayed(runnable, interval);
}
public class MyLocalBinder extends Binder {
BoundService getService() {
return BoundService.this;
}
}
}
Activity:
public class MainActivity extends Activity {
BoundService myService;
boolean isBound = false;
public void test(View view)
{
myService.testNotification();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, BoundService.class);
startService(intent);
bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection myConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
MyLocalBinder binder = (MyLocalBinder) service;
myService = binder.getService();
isBound = true;
}
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
Thanks
Manual says: "When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it". Thats why your handler works in activity thread and can't continue to process events after activity was killed. Try something like this in your service:
Thread worker = null;
Handler handler = null;
#Override
public void onCreate() {
worker = new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
handler = new Handler();
Looper.loop();
}
});
worker.start();
}
#Override
public void onDestroy() {
handler.getLooper().quit();
worker = null;
handler = null;
}
Edit:
You must also call startForeground within your service (using some notification) because activity manager kills app process when you closing app if there are no foreground service running and service crashes and will be restarted later because of START_STICKY. It is strange behavior but I saw this on real device too.
I've got a Sticky Service (returns START_STICKY from onStartCommand) which executes some code in an AsyncTask, but I'm having some problems with how and when to start, bind, stop, unbind. I only want the service around whilst the parent activity is alive, I don't want it hanging around in the background when the app has been closed, but I need the service to survive an orientation change. I currently don't need the service to be active for the entire duration of the activity being active, so I call stopSelf() after the main work is done in my AsyncTask in the Service and then start the Service again when needed. Sometimes I'll need to interrupt the work the service is doing, cancel the AsyncTask and start again with different data. The problem is that no matter what I do - I can't seem to get it solid throughout all the different possible scenarios. Can anyone have a look through and tell me what I'm doing wrong?
My Service is :
public class ChordCalculatorService extends Service {
private final IBinder mBinder = new LocalBinder();
private AsyncTask<SearchData, SearchStatusData, List<Item>> currentTask;
#Override
public void onCreate() {}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
/**
* Class for clients to access. Because we know this service always runs in
* the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
public ChordCalculatorService getService() {
return ChordCalculatorService.this;
}
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public SearchData getSearchData() {
return searchData;
}
public void startWork() {
if (currentTask != null && currentTask.getStatus() == Status.RUNNING) {
currentTask.cancel(true);
}
if(searchData != null) {
Worker task = new Worker();
currentTask = task.execute(new SearchData[] { searchData });
} else {
Message msg = handler.obtainMessage(ERROR, "No search data set");
handler.sendMessage(msg);
}
}
class Worker extends AsyncTask<SearchData, SearchStatusData, List<Item>> {
// ... code ...
#Override
protected void onPostExecute(List<Item> result) {
Message msg = handler.obtainMessage(COMPLETE, new StatusData(Status.STATUS_FINISHED, result));
handler.sendMessage(msg);
stopSelf();
}
}
}
Currently I have the Service being started when my custom View is created:
public class MyCustomView extends BasicFretBoardView {
private ServiceConnection conn;
private MyService myService;
private boolean isServiceStarted;
private boolean isServiceBound;
public MyCustomView(Context context, AttributeSet attr) {
super(context, attr);
startService();
}
public void startService() {
Intent serviceIntent = new Intent(getContext(), MyService.class);
conn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
myService = ((LocalBinder) service).getService();
myService.registerHandler(serviceHandler);
}
#Override
public void onServiceDisconnected(ComponentName name) {
myService = null;
}
};
// Explicitly start the service. Don't use BIND_AUTO_CREATE, since it
// causes an implicit service stop when the last binder is removed.
getContext().startService(serviceIntent);
getContext().bindService(serviceIntent, conn, 0);
isServiceStarted = true;
isServiceBound = true;
}
public void stopService() {
if (isServiceStarted) {
Intent serviceIntent = new Intent(getContext(), MyService.class);
getContext().stopService(serviceIntent);
isServiceStarted = false;
}
unBindService();
}
public void unBindService() {
if(isServiceBound) {
getContext().unbindService(conn);
isServiceBound = false;
}
}
// gets called based on some user interaction
private void startServiceWork() {
if(!isServiceStarted) {
startService();
} else {
myService.cancelCalcalation();
}
myService.setData(data);
myService.startWork();
}
}
and stopping the service is handled in the Activity:
public class CustomChordActivity extends Activity {
// ... code ...
#Override
public void onBackPressed() {
super.onBackPressed();
}
#Override
protected void onPause() {
if(isFinishing()) {
chordsView.stopService();
}
super.onPause();
}
#Override
protected void onStop() {
super.onStop();
}
#Override
protected void onDestroy() {
chordsView.unBindService();
super.onDestroy();
}
#Override
protected void finalize() throws Throwable {
super.finalize();
}
}
It seems that you want your task to run on demand, maybe an IntentService would be a more suitable option. When you need work to be done, (startServiceWork()), you just start the service and that kicks off your AsyncTask. The service will then finish after the task has finished.
Now, regarding orientation changes, you would have to implement a Broadcast Receiver whose intent filter is "android.intent.action.CONFIGURATION_CHANGED". (I assume that you want the service to do work when the orientation changes) Place the Broadcast Receiver, within your activity/main ui thread. This will in effect make the hosting process of your Broadcast Receiver to be the main application process making it safer to start the service from within the Broadcast Receiver.