Sticky service not restarting when created in custom object - android

I had a Singleton object that had a bound service. I wanted it to restart, and when I start my application from launcher, singleton object will initialize and bind to this existing instance of service.
Here is the code for creating and binding service in singleton:
public class MyState {
private static MyState sState;
private MyService mService;
private Context mContext;
private boolean mBound = false;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyService.MyBinder binder = (MyService.MyBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
};
public static MyState get(Context context) {
if (sState == null) {
sState = new MyState(context);
}
return sState;
}
public MyState(Context context) {
mContext = context.getApplicationContext();
startService();
}
private void startService() {
Intent intent = new Intent(mContext, MyService.class);
mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
// this won't create another instance of service, but will call onStartCommand
mContext.startService(intent);
}
}
And here is the code insice Service
public class MyService extends Service {
private final IBinder mBinder = new MyBinder();
public class MyBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// this method is called by singleton object to stop service manually by user
public void stop() {
stopSelf();
}
#Override
public void onDestroy() {
super.onDestroy();
// some cleanup code here
}
}
Unfortunately, when I swipe away my app in task list this service never restarts. Service's onDestroy method is never called in this case.
I moved the binding to an activity at which user can interact with service, and surprisingly it started working as I expected.
I tried to call service creation using application context inside my activity, and it still works.
Is starting service from activity different from starting it from a regular java object?

As you are returning START_STICKY this service will stop whenever you close/kill the app because after the App closed all the Reference/Value will become null for all Intent as well as variables and so STICKY service will not able to get Intent value. if you want to restart the service after app kills use return START_REDELIVER_INTENT
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_REDELIVER_INTENT;
}
this will restart the service in 5-10 seconds after app killed.

Related

service got stopped when the app goes background

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.

how to start service and stop it at another activity in android

my Service never stop until I uninstall the app #HELP!
service class
public class LocationService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
GPSTracker myGps = new GPSTracker(getApplicationContext());
Log.e("tracking...","");
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public boolean stopService(Intent name) {
GPSTracker myGps = new GPSTracker(getApplicationContext());
Log.e("STOPPED!","");
return super.stopService(myGps);
}
}
** Start the Service At the Login Activity**
Intent locationService = new Intent(Login.this, LocationService.class);
startService(locationService);
**Stop the service At the employee Activity in option selected menu **
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent serviceIntent;
int id = item.getItemId();
if (id == R.id.LogOut) {
serviceIntent = new Intent(Employee.this, LocationService.class);
stopService(serviceIntent);
Log.e("OUT"," ");
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
In the 2 activities A and B u have, you should unbind service in B onStop(), then you can call stopService in A. Simply putting stopService(serviceIntent); might give you and error about leaked service connection
protected ServiceConnection mServerConn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.d(LOG_TAG, "onServiceConnected");
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d(LOG_TAG, "onServiceDisconnected");
}
}
public void start() {
// mContext is defined upper in code, I think it is not necessary to explain what is it
mContext.bindService(i, mServerConn, Context.BIND_AUTO_CREATE);
mContext.startService(i);
}
public void stop() {
mContext.stopService(new Intent(mContext, ServiceRemote.class));
mContext.unbindService(mServerConn);
}
and see in your code what you have done is u have stopped the service but i dont see you unbinding it, the correct procedure would be unbind it then stop it.
Dont use the command startService(service).
To start the service at the beginning of the app just bind it to all your activities. This way, when the activities are destroyed, the service stops.
Explained thoroughly HERE
Also, if you want the service to end when the app is closed(but not destroyed), just add unBindService method to an overrided onStop method.

My background music service stops when I load a new activity. Am I connecting or binding wrong?

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.

Passing parameter from an activity to a thread in a service

I have an activity in which I start a service, for example I staty MyService as:
Intent intent1 = new Intent(this, MyService.class);
startService(intent1);
Inside my service I create a thread and run it. Here is part of my code:
public class MyService extends Service {
...
#Override
public void onStart(Intent intent, int startid) {
Thread mythread= new Thread() {
#Override
public void run() {
while(true)
{
...
}
}
};
mythread.start();
}
}
Now instead of while(true) I want to use while(a), where a is a parameter that is passed from my activity to this service. Please note that my activity is a different class than my service. How can this be done? Please show specific example with some codes.
You can get access to your service by binding to it. Edit your service class so that it returns an IBinder onBind()
public class MyService extends Service {
private static final String TAG = MyService.class.getSimpleName();
private final IBinder binder = new ServiceBinder();
private boolean a;
#Override
public IBinder onBind( Intent intent ) {
return binder;
}
#Override
public int onStartCommand( Intent intent, int flags, int startId ) {
return super.onStartCommand( intent, flags, startId );
}
#Override
public void onCreate() {
super.onCreate();
}
public class ServiceBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
public void setA(boolean a) {
this.a = a;
}
}
Now in your activity you need to handle binding and unbinding to your service. In this example, the service sticks around whether you are bound or not. If this is not the functionality you want, you can just not call startService(...):
public class MyActivity extends Activity {
//...
private MyService myService;
private boolean bound;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent( this, MyService.class );
startService( intent );
doBindService();
}
private final ServiceConnection serviceConnection = new ServiceConnection() {
public void onServiceConnected( ComponentName className, IBinder service ) {
myService = ( (MyService.ServiceBinder) service ).getService();
bound = true;
}
public void onServiceDisconnected( ComponentName className ) {
myService = null;
bound = false;
}
};
void doBindService() {
boolean bound = bindService( new Intent( this, MyService.class ), serviceConnection, Context.BIND_AUTO_CREATE );
if ( bound ) {
Log.d( TAG, "Successfully bound to service" );
}
else {
Log.d( TAG, "Failed to bind service" );
}
}
void doUnbindService() {
unbindService( serviceConnection );
}
}
Now you have a reference to your bound service in your activity and you can just call myService.setA(true) to set your parameter.
Instead of calling start service use bindService which allows you access to the service object.
Here is a detailed topic about it Android Doc
Once your activity is bound to your service you can call from your activity any method from your service.
you could do something like this:
.... Activity Code
mService.stopThread();
..... Service Code
public void stopThread(){
a = false;
}
Here is How I do it:
In your activity when you try to connect to the service :
Intent serviceIntent = new Intent(this, MyService.class);
bindService(serviceIntent, serviceConnection, BIND_AUTO_CREATE);
private ServiceConnection serviceConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
mService = (MyService) ((MyService.LocalBinder) arg1)
.getService();
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
// TODO Auto-generated method stub
}
};
And In my service :
I add this member
private LocalBinder mBinder;
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
mBinde = new LocalBinder();
}
and this class:
public class LocalBinder extends Binder {
public MyService getService() {
// Return this instance of LocalService so clients can call public
// methods
return MyService.this;
}
}
I think service binding will be overkill for your case, since you have simple interaction between the activity and your service.
As suggested, you can pass the parameters using startService. Another solution, is to use LocalBroadcast, here is an example
Regarding your thread, you might need to define it as separate class in your service not anonymous class, for example:
class MyThread extends Thread{
private boolean a = true;
public void setA(boolean a){
this.a = a;
}
public void run() {
while(a)
{
...
}
}
}
Simple Use
Intent intent1 = new Intent(this, MyService.class);
intent1.putExtra("key",value);
startService(intent1);
and retrieve it in service using
a = intent.getStringExtra("key");// or Int, ArrayList whatever
If I have understood the question correctly, this is what you need:
In the activity class, right before calling startService(), add this line:
intent1.putExtra("keyName","keyValue");
In the service, in onStartCommand():
Bundle extras = intent.getExtras();
String param = extras.getString("keyName");
param will hold your parameter.

Sticky Service Management

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.

Categories

Resources