I have a service that is always running. It can be started and bound to as well. Here is an excerpt of the service:
class LocalService extends Service {
LocalBinder mBinder = new LocalBinder();
class LocalBinder extends Binder {
LocalService getService() { return LocalService.this; }
}
int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
IBinder onBind(Intent intent) {
return mBinder;
}
}
This service is started on application launch by the MainActivity:
class MainActivity extends AppCompatActivity {
void onCreate(Bundle) {
// ...
Intent intent = new Intent(this, LocalService.class);
ComponentName component = startService(intent);
Assert.assertNotNull(component);
}
}
I need to pass commands to my service. In order to do that, I have an abstract service LocalBindingService that I can inherit from that when started, binds to my service, call a method on it, then exits:
class LocalBindingService extends IntentService implements ServiceConnection {
abstract void onLocalBinding(Intent intent, LocalService service);
Intent mIntent;
void onHandleIntent(Intent intent) {
mIntent = intent;
Intent localIntent = new Intent(this, LocalService.class);
boolean serviceFound = bindService(localIntent, this, Context.BIND_AUTO_CREATE);
Assert.assertTrue(serviceFound);
}
void onDestroy() {
unbindService(this);
super.onDestroy();
}
void onServiceConnected(ComponentName name, IBinder iBinder) {
LocalService service = ((LocalService.LocalBinder) iBinder).getService();
onLocalBinding(mIntent, service);
}
void onServiceDisconnected(ComponentName) {
// nothing
}
}
Since it inherits from IntentService it runs in a separate thred. This way it should be easy to simply invoke a method on LocalService:
class NotifyService extends LocalBindingService {
void onLocalBinding(Intent intent, LocalService service) {
service.notify();
}
}
However, my problem is that LocalBindingService exits before binding occurs. From what I gather, it should inherit from Service instead of IntentService, which means I have to handle the thread manually. When looking at the example from the Android guide, I fail to understand how to adapt my code. I don't really understand this use of Looper in the example and whether I need it at all.
Could someone help me adapt this piece of code to achieve this behavior? Thanks,
Related
My app use a background music service.
I have a button to quit my app but I can't find anything to close my app and my service.
I bind my service to my activity.
I tried:
unbindService(serviceConnection);
myService().stopSelf();
stopService(new Intent(this, MediaPlayer.class));
and absolutely nothing works !!! The service continues.
How can I do to destroy my service and how can I do to close my app ??
Tx
EDIT:
I use this in the onCreate method
Intent intent = new Intent(this, serviceClass);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
And in the MediaPlayer class
public class LocalBinder extends Binder {
public MediaPlayer getService() {
return MediaPlayer.this;
}
}
public IBinder onBind(Intent intent) {
Log.i(TAG, "service bound");
init();
return mBinder;
}
And that...
But I dont know if I really need to start the service. Bind the service already starts it
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
Now I did this
#Override
public void onDestroy() {
player.stop();
super.onDestroy();
}
The onDestroy method works only if i unbind the service !
This doesnt work at all:
getService().stopSelf();
this.stopService(new Intent(this, MediaPlayer.class));
So, how can I stop the service and how can I close the app ?
This is what I do in my app. onDestroy() method from the activity will be called when you close your app.
private ServiceConnection musicServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.LocalBinder binder = (MusicService.LocalBinder) service;
musicService = binder.getService();
musicService.setCallbacks(MainActivity.this);
musicServiceBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "MusicService service disconnected (unbinded)");
musicServiceBound = false;
}
};
#Override
protected void onStart() {
super.onStart();
Intent intent1 = new Intent(this, MusicService.class);
bindService(intent1, musicServiceConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onDestroy() {
super.onDestroy()
if(musicServiceBound){
musicService.stopSelf();
unbindService(musicServiceConnection);
}
}
You wrote myService(), where you are creating another service using ().
For closing your app programmatically you can refer to this question.
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.
Issues
Service is NOT running always even after I have used START_STICKY.
Sometimes I dont get any Toast Action for Outgoing call, is that mean service stops after some time ?
My Requirment
Application shows a Toast whenever user makes a outgoing call from the phone. For this I am using a BroadcastReceiver to tap the call action and a service (to run Receiver always). once I start this activity, it starts showing toast when a outgoing call get initiated ..but not Always.
Below is the complete code -
MainActivity.class
public class MainActivity extends Activity
{
CallNotifierService m_service;
boolean isBound = false;
private ServiceConnection m_serviceConnection = new ServiceConnection()
{
#Override
public void onServiceConnected(ComponentName className, IBinder service)
{
m_service = ((CallNotifierService.MyBinder)service).getService();
Toast.makeText(MainActivity.this, "Service Connected", Toast.LENGTH_LONG).show();
isBound = true;
Intent intent = new Intent(MainActivity.this, CallNotifierService.class);
startService(intent);
}
#Override
public void onServiceDisconnected(ComponentName className)
{
m_service = null;
isBound = false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, CallNotifierService.class);
bindService(intent, m_serviceConnection, Context.BIND_AUTO_CREATE);
}
.
.
.
}
CallNotifierService.class
public class CallNotifierService extends Service
{
private final IBinder myBinder = new MyBinder();
private static final String ACTION_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
private CallBr br_call;
#Override
public IBinder onBind(Intent arg0)
{
return myBinder;
}
#Override
public void onDestroy()
{
Log.d("service", "destroy");
this.unregisterReceiver(this.br_call);
Toast.makeText(CallNotifierService.this, "Receiver Un-Registered", Toast.LENGTH_LONG).show();
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_OUTGOING_CALL);
this.br_call = new CallBr();
this.registerReceiver(this.br_call, filter);
Toast.makeText(CallNotifierService.this, "onStartCommand Called", Toast.LENGTH_LONG).show();
return START_STICKY;
}
public class MyBinder extends Binder
{
CallNotifierService getService()
{
return CallNotifierService.this;
}
}
public class CallBr extends BroadcastReceiver
{
public CallBr() {}
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Action:"+intent.getAction(), Toast.LENGTH_LONG).show();
}
}
}
You are getting the wrong approach here, by mixing a simple idea (that would work if done correctly) with more complicated ideas (that cannot work).
Keep in mind: services are not "always running" components, even when using START_STICKY.
The Android system will not hesitate to kill your service if it needs memory somewhere else. START_STICKY only means that the Android system will re-start your service when it can, calling onStartCommand as specified in the documentation.
If you need a service to really stick around, then you must use a foreground service. But it will have consequences on the UI (annoying notification icon always showing), and battery life, and you do not need this here.
Now here is the magic trick: your app does not need to be running for your BroadcastReceiver to work. All you need to do is to register it in your AndroidManifest.xml with the correct intent-filter:
<receiver android:name=".broadcastreceivers.CallBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
(also make sure your app has the required permissions, namely PROCESS_OUTGOING_CALLS).
Then all you need in code is:
public class CallBroadcastReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Action: " + intent.getAction(), Toast.LENGTH_LONG).show();
}
}
No activity (except to ask for the PROCESS_OUTGOING_CALLS permission on Android 6+), no service, nothing. Simple and battery-efficient !
The service does get re-created, not not re-started.
If you override the onCreate and do a Log.d or a Toast, you will see that it gets called after your app is destroyed.
So the trick to keep it running after it is recreated is to do your code on the onCreate method and use the onStartCommand just to return START_STICKY.
I am stuck with getting my Android Service running and would really need some help.
I started off with Vogella's Tutorial on how to bind a Service and ended up trying out pretty much every approach which came to my mind and on the web to solve my problem.
"onStart()" of my main Activity gets called and no Exception (creating Intent, "bindService()") is thrown. But, also, no Service is started (apiService == null).
I know it shouldn't be hard to get it working, but sadly I am stuck with this for over two hours already. Any kind of help, pointers, etc. is really appreciated.
[EDIT]
Breakpoints set in the service class don't get hit. Also, Log.d() entries won't print in Logcat.
Service extending Android.Service and implementing my own Interface:
public class APIService extends Service implements APICall{
private final IBinder binder = new APIBinder();
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId){
super.onStartCommand(intent, flags, startId);
return Service.START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
public class APIBinder extends Binder{
public APIService getService(){
return APIService.this;
}
}
//implementation of Interface...
Main Activity / binding of Service:
public class MainActivity extends Activity {
private APIService apiService = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
super.onStart();
Intent serviceIntent = new Intent(this, APIService.class);
bindService(serviceIntent, apiServiceConnection, Context.BIND_AUTO_CREATE);
};
#Override
protected void onDestroy(){
super.onDestroy();
unbindService(apiServiceConnection);
}
private ServiceConnection apiServiceConnection = new ServiceConnection(){
public void onServiceConnected(ComponentName className, IBinder binder) {
APIBinder localBinder = (APIBinder)binder;
apiService = localBinder.getService();
}
public void onServiceDisconnected(ComponentName className) {
apiService = null;
}
};
//click handler, etc...
Manifest file entry:
<service android:name=".APIService"/>
You should add
startService(serviceIntent);
before
bindService(serviceIntent, apiServiceConnection, Context.BIND_AUTO_CREATE);
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.