I'm having some problems with services.
Service:
public class MyService extends Service {
public MyService() {
}
private static final String TAG = "AutoService";
private Timer timer;
private TimerTask task;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Auto Service Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
int delay = 5000; // delay for 5 sec.
int period = 5000; // repeat every sec.
timer = new Timer();
timer.scheduleAtFixedRate(task = new TimerTask(){
public void run()
{
System.out.println("done");
}
}, delay, period);
}
#Override
public boolean stopService(Intent name) {
timer.cancel();
task.cancel();
return super.stopService(name);
}
#Override
public void onDestroy(){
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_SHORT).show();
super.onDestroy();
}
MainActivity:
public class ClientSocket extends ActionBarActivity {
CheckBox enablecheck;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client_socket);
enablecheck = (CheckBox)findViewById(R.id.enablecheck);
enablecheck.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
if(enablecheck.isChecked()){
startService(new Intent(ClientSocket.this, MyService.class));
}else
{
stopService(new Intent(ClientSocket.this, MyService.class));
}
}
});
}
Manifest file:
<?xml version="1.0" encoding="utf-8"?>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/Theme.AppCompat.Light" >
<activity
android:name=".ClientSocket"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" >
</service>
</application>
I'm just testing, when I try to stop the service, the fuction onDestroy() is called but don't stop the service. The service/android:exported and android:enable both are true.
Any help?
The Timer instance create a background thread. If you want to stop the service completely you also need to stop the thread. Timer has a cancel() method you can call in the onDestroy() method to terminate the Timer.
Also, exporting the service means other applications (processes) can access it. You most likely don't need that.
The issue in the code is a misunderstanding of what
#Override
public boolean stopService(Intent name) {
timer.cancel();
task.cancel();
return super.stopService(name);
}
really does.
It is not a callback that is called when the service is stopped. Instead it is overriding the stopService method on Context, which you call to stop a service (as you do in the Activity in your example).
In fact the override of stopServicein your code has no effect at all.
timer.cancel();
task.cancel();
should be placed in the onDestroy method of your service.
Related
My service extends IntentService and when it is started with startService, onHandleIntent gets called. However, when the service is started with bindService (I do need binding), onHandleIntent does not get called.
Should onHandleIntent be called when IntentService is started with bindService? Is startService the only way IntentService should be started?
The documentation for IntentService says the following:
Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
Currently I solve my problem by calling startService right after bindService but I find it ugly. I would like to know is there a way to make it work with just one call.
Code snippets follow, it might be that I am missing something obvious.
ExampleService.java
public class ExampleService extends IntentService {
private class IncomingHandler extends Handler {
#Override
public void handleMessage(Message message) {
if (message.replyTo != null) {
outMessenger = message.replyTo;
}
}
}
private Messenger messenger = new Messenger(new IncomingHandler());
private Messenger outMessenger = null;
public ExampleService() {
super("ExampleService");
}
#Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
#Override
protected void onHandleIntent(Intent arg0) {
System.out.println("Service started");
for (int i = 0; i < 5; i++) {
SystemClock.sleep(5000);
if (outMessenger != null) {
try {
outMessenger.send(Message.obtain());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Service Manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.service"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="3"
android:targetSdkVersion="15" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".ExampleService">
<intent-filter>
<action android:name="com.example.service.ExampleService" />
</intent-filter>
</service>
</application>
</manifest>
MainActivity.java (caller)
public class MainActivity extends Activity implements ServiceConnection {
private class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "Message received", Toast.LENGTH_SHORT).show();
System.out.println("Message received!");
super.handleMessage(msg);
}
}
private Messenger messenger = new Messenger(new IncomingHandler());
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent("com.example.service.ExampleService");
bindService(intent, MainActivity.this, Context.BIND_AUTO_CREATE);
//startService(intent);
}
});
}
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Message message = Message.obtain();
message.replyTo = messenger;
try {
new Messenger(binder).send(message);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
Should onHandleIntent be called when IntentService is started with bindService?
No.
Is startService the only way IntentService should be started?
IMHO, yes. IMHO, IntentService is not designed for the binding pattern.
In your case, you can:
Pass a Messenger from the activity in an Intent extra in the command sent by startService(), or
Use LocalBroadcastManager, or
Use Otto, or
Use an ordered broadcast, if the IntentService might continue past the activity's life and you want to, say, display a Notification when the work gets done in that case,
Etc.
You must call both startService and bindService.
This was worked for me.
I'm trying to start a service on android in order to performe some network-related tasks in background. I have written a basic network-manager for my app, which is a service. I basically used the tutorial from the android documentation. The basic structure goes as following:
public class MyNetworkManager extends Service {
// some code
private final IBinder mBinder = (IBinder) new MyBinder();
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class MyBinder extends Binder {
MyNetworkManager getService() {
return MyNetworkManager.this;
}
}
public void onCreate() {
// some network related stuff like setting up sockets etc.
}
public void onStart(Intent intent, int startid) {
while(true) {
// receive new connections etc
}
}
The calling app/activity is then:
public class AndroidNetworkManagerClient extends Activity {
private Button buttonSend;
private EditText inputText;
private TextView outputText;
private MyNetworkManager networkManager;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
networkManager = ((MyNetworkManager.MyBinder) binder).getService();
}
public void onServiceDisconnected(ComponentName className) {
networkManager = null;
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
inputText = (EditText) findViewById(R.id.textInput);
outputText = (TextView) findViewById(R.id.textOutput);
buttonSend = (Button)this.findViewById(R.id.buttonSend);
buttonSend.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (inputText.getText().length() != 0) {
outputText.append("Out: " + inputText.getText() + "\n");
networkManager.sendData("localhost", inputText.getText().toString());
}
}
});
bindService(new Intent(this, MyNetworkManager.class), mConnection, Context.BIND_AUTO_CREATE);
doSomeAppRelatedStuff();
}
bindService() seems to be called without any problems, but the variable "networkManager" is always null! I already tried to debug into the onCreate() method or onServiceConnected() but it seems, that these parts are not reached at all (at least no breakpoint was triggered).
The service is already registered in the AndroidManifest.xml:
package="some.random.name"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".AndroidNetworkManagerClient"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyNetworkManager"></service>
</application>
Anyone an idea?
Chances are, your Activity is getting into doSomeAppRelatedStuff() and trying to use networkManager before the binding is complete.
If doSomeAppRelatedStuff() absolutely must have the network manager to function, move your call to doSomeAppRelatedStuff() into onServiceConnected() so it won't actually start until the binding is complete. Note that if you do that, your onStart() and onResume() calls will probably (but not guaranteed!) happen before the binding is complete, so program accordingly.
i'm a java noob, so sorry for the noob question...
i have a checkbox that is supposed to fire off a service when checked - kill it when unchecked.
the "attempting..." toast pops up as expected, but the services does not seem to be starting and does not present toast..
here are my mainifest entries, main activity code (abbridged), and the service code:
// manifest entries
<application android:icon="#drawable/ic_launcher" android:label="#string/app_name" >
<activity android:name=".MainMenu" android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".PPS" android:process=":remote" android:label="#string/service_name" />
</application>
// MainMenu.java
final CheckBox checkBoxStartService = (CheckBox) findViewById(R.id.checkBoxEnable);
checkBoxStartService.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if (checkBoxStartService.isChecked() == true)
{ // make toast
Toast toaster = Toast.makeText(MainMenu.this, "attempting to start service...", 500);
toaster.setGravity(Gravity.CENTER, 0, -200);
toaster.show();
Intent startPPS = new Intent();
startPPS.putExtra("com.domain.notlaunchingservice.PPS", false);
startService(startPPS);
}
if (checkBoxStartService.isChecked() == false)
{
Intent closePPS = new Intent();
closePPS.putExtra("com.domain.notlaunchingservice.PPS", true);
stopService(closePPS);
}
}
};
// PPS.java
package com.domain.notlaunchingservice;
import android.app.Service;
import android.view.Gravity;
import android.widget.Toast;
public abstract class PPS extends Service
{
#Override
public void onCreate()
{
Toast toasty = Toast.makeText(PPS.this, "service created!", 500);
toasty.setGravity(Gravity.CENTER, 0, 200);
toasty.show();
};
public void onDestroy()
{
Toast toasted = Toast.makeText(PPS.this, "service destroyed!", 500);
toasted.setGravity(Gravity.CENTER, 0, -200);
toasted.show();
};
};
i have also tried to call the service using:
startService(new Intent(MainMenu.this, PPS.class));
this returns an error on the emulator saying the app quit unexpectedly and i click force close, but the main activity doesn't close, so i'm assuming it's the service that i am force closing.
below is the DDMS output:
java.lang.RuntimeException: Unable to instantiate service com.domain.notlaunchingservice.PPS
i don't care how i get the service started, as long as it can load a SQL base and continue recording audio to a file after the main activity loses focus or is closed.
this will be a free app on the market when finished, so your help will be appreciated by many when the project is ready for prime time.
thanks for reading
One problem is that the intent you use to start and stop the service only specifies an extra.
Intent startPPS = new Intent();
should be
Intent startPPS = new Intent(this, PPS.class);
But there are other problems as well (I don't think your example compiles), I would recommend you to look at the example at http://developer.android.com/guide/topics/fundamentals/services.html#ExtendingIntentService
Edit: (example code below)
public class StartedService extends Service {
#Override
public IBinder onBind(Intent intent) {
// I guess that you don't want to bind to the service
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Service is running", Toast.LENGTH_SHORT).show();
// Return sticky if you want it to be restarted in a low memory
// situation
return START_STICKY;
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service is going down", Toast.LENGTH_SHORT).show();
}
}
public class ClientActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button startButton = (Button)findViewById(R.id.start_button);
startButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
startService(new Intent(ClientActivity.this, StartedService.class));
}
});
Button stopButton = (Button)findViewById(R.id.stop_button);
stopButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
stopService(new Intent(ClientActivity.this, StartedService.class));
}
});
}
}
I've been studying from the book "Pro Android 2." I'm working through a Service example that consists of two classes: BackgroundService.java and MainActivity.java. The MainActivity claims (erroneously?) it starts the Service as indicated by output to logcat from the Log.d call below:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(TAG, "starting service");
Button bindBtn = (Button)findViewById(R.id.bindBtn);
bindBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent backgroundService = new Intent(MainActivity.this, com.marie.mainactivity.BackgroundService.class);
startService(backgroundService);
}
});
Button unbindBtn = (Button)findViewById(R.id.unbindBtn);
unbindBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
stopService(new Intent(MainActivity.this, BackgroundService.class));
}
});
}
}
What puzzles me is the UI provides two buttons: Bind and UnBind as shown above. But according to the documentation if onBind() as shown below returns null that indicates you don't want to allow binding. But as shown above the onClick() method of (the Bind button) bindBtn.setOnClickListener(new OnClickListener() calls startService(backgroundService) which gives this error:"Unable to start service Intent { cmp=com.marie.mainactivity/.BackgroundService }: not found"
public class BackgroundService extends Service {
private NotificationManager notificationMgr;
#Override
public void onCreate() {
super.onCreate();
notificationMgr = NotificationManager)getSystemService(NOTIFICATION_SERVICE);
displayNotificationMessage("starting Background Service");
Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");
thr.start();
}
class ServiceWorker implements Runnable
{
public void run() {
// do background processing here...
//stop the service when done...
//BackgroundService.this.stopSelf();
}
}
#Override
public void onDestroy()
{
displayNotificationMessage("stopping Background Service");
super.onDestroy();
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void displayNotificationMessage(String message)
{
Notification notification = new Notification(R.drawable.note, message, System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
notification.setLatestEventInfo(this, "Background Service", message, contentIntent);
notificationMgr.notify(R.id.app_notification_id, notification);
}
}
I don't understand the point of this example. If onBind() returns null what's the point of having a Bind button (bindBtn)? I thought the point was to show how to start a BackgroundService. But it doesn't seem to work unless I'm missing something.
I should add I have added to my AndroidManifest.xml:
<service android:name=".BackgroundService"></service>
as follows:
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<service android:name=".BackgroundService"></service>
</activity>
</application>
Remove the service from inside the activity. It is at the same level as the activity within the application. Eg:
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".BackgroundService"></service>
</application>
I am trying to call my service class's stopService() method from my activity.
But I dont know how to access stopservice method from my activity class.
I have the below code but its not working...........
This is HomeScreen class:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
enablecheck = (CheckBox)findViewById(R.id.enablecheck);
enablecheck.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
if(enablecheck.isChecked()){
startService(new Intent(HomeScreen.this, AutoService.class));
}else
{
stopService(new Intent(HomeScreen.this, AutoService.class));
}
}
});
}
This is Service Class:
public class AutoService extends Service {
private static final String TAG = "AutoService";
private Timer timer;
private TimerTask task;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Auto Service Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
int delay = 5000; // delay for 5 sec.
int period = 5000; // repeat every sec.
timer = new Timer();
timer.scheduleAtFixedRate(task = new TimerTask(){
public void run()
{
System.out.println("done");
}
}, delay, period);
}
#Override
public boolean stopService(Intent name) {
// TODO Auto-generated method stub
timer.cancel();
task.cancel();
return super.stopService(name);
}
}
Any suggestion highly appreciable.
Thanks and Regards
Mintu
In fact to stopping the service we must use the method stopService() and you are doing in right way:
Start service:
Intent myService = new Intent(MainActivity.this, BackgroundSoundService.class);
startService(myService);
Stop service:
Intent myService = new Intent(MainActivity.this, BackgroundSoundService.class);
stopService(myService);
if you call stopService(), then the method onDestroy() in the service is called (NOT the stopService() method):
#Override
public void onDestroy() {
timer.cancel();
task.cancel();
Log.i(TAG, "onCreate() , service stopped...");
}
you must implement the onDestroy() method!.
Here is a complete example including how to start/stop the service.
I actually used pretty much the same code as you above. My service registration in the manifest is the following
<service android:name=".service.MyService" android:enabled="true">
<intent-filter android:label="#string/menuItemStartService" >
<action android:name="it.unibz.bluedroid.bluetooth.service.MY_SERVICE"/>
</intent-filter>
</service>
In the service class I created an according constant string identifying the service name like:
public class MyService extends ForeGroundService {
public static final String MY_SERVICE = "it.unibz.bluedroid.bluetooth.service.MY_SERVICE";
...
}
and from the according Activity I call it with
startService(new Intent(MyService.MY_SERVICE));
and stop it with
stopService(new Intent(MyService.MY_SERVICE));
It works perfectly. Try to check your configuration and if you don't find anything strange try to debug whether your stopService get's called properly.
#Juri
If you add IntentFilters for your service, you are saying you want to expose your service to other applications, then it may be stopped unexpectedly by other applications.
That looks like it should stop the service when you uncheck the checkbox. Are there any exceptions in the log? stopService returns a boolean indicating whether or not it was able to stop the service.
If you are starting your service by Intents, then you may want to extend IntentService instead of Service. That class will stop the service on its own when it has no more work to do.
AutoService
class AutoService extends IntentService {
private static final String TAG = "AutoService";
private Timer timer;
private TimerTask task;
public onCreate() {
timer = new Timer();
timer = new TimerTask() {
public void run()
{
System.out.println("done");
}
}
}
protected void onHandleIntent(Intent i) {
Log.d(TAG, "onHandleIntent");
int delay = 5000; // delay for 5 sec.
int period = 5000; // repeat every sec.
timer.scheduleAtFixedRate(timerTask, delay, period);
}
public boolean stopService(Intent name) {
// TODO Auto-generated method stub
timer.cancel();
task.cancel();
return super.stopService(name);
}
}
In Kotlin you can do this...
Service:
class MyService : Service() {
init {
instance = this
}
companion object {
lateinit var instance: MyService
fun terminateService() {
instance.stopSelf()
}
}
}
In your activity (or anywhere in your app for that matter):
btn_terminate_service.setOnClickListener {
MyService.terminateService()
}
Note: If you have any pending intents showing a notification in Android's status bar, you may want to terminate that as well.