I have implemented an android service which performs following long operations
when screen goes off start recording accelerometer data.
When data reaches 3000 samples I write it to the file.
then I perform data processing on the after reading recorded data.
Then I extract gait template from that data.
Then I compute similarity score.
I want to keep that service running as long as user explicitly does not quit this service.
In case if screen goes on I stop data recording and check if number of samples are more than minimum number of samples i repeat steps 2-5. else just drop recorded samples.
I have a broadcast receiver to get SCREEN_ON and SCREEN _OFF broadcasts writing file works fine but time taking part is feature (or template generation) I read from android documentation
A service runs in the main thread of its hosting process—the service does not create its own thread and does not run in a separate process (unless you specify otherwise). This means that, if your service is going to do any CPU intensive work or blocking operations (such as MP3 playback or networking), you should create a new thread within the service to do that work. By using a separate thread, you will reduce the risk of Application Not Responding (ANR) errors and the application's main thread can remain dedicated to user interaction with your activities.
Therefore I am trying to implement service with background thread. But still i am getting anr errors any help ?.
public class GaitAuthenticationService extends Service {
int mStartMode; // indicates how to behave if the service is killed
IBinder mBinder; // interface for clients that bind
boolean mAllowRebind; // indicates whether onRebind should be used
private int serviceState = 0; // This will maintain state of our service
private BroadcastReceiver screenOnOffReceiver = new ScreenOffBroadCastReciever();;
private SensorManager mSensorManager;
private PowerManager mPowerManager;
private PowerManager.WakeLock mLock;
private AccelRecorderTesting mAccelRecorder;
private Context context;
private boolean screenOff;
private KeyguardManager keyGaurdManager;
private boolean screenState;
private IntentFilter mfilter;
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
if (screenState==true && (keyGaurdManager.isKeyguardLocked() || keyGaurdManager.isKeyguardSecure())){
Log.d("SCREEN ON OFF RECIEVER","screen is oFF(onStartCommand)");
Log.d("GaitAuthenticationService", "Started recording data");
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
mAccelRecorder.onStartButtonIsClicked();
}
// stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
mAccelRecorder = new AccelRecorderTesting();
keyGaurdManager = (KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE);
mAccelRecorder = new AccelRecorderTesting(this.getApplicationContext());
Log.i("GaitAuthenticationService", " is started");
mfilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
mfilter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(screenOnOffReceiver, mfilter);
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",new Process().THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#SuppressLint("NewApi")
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// The service is starting, due to a call to startService()
// if(intent!=null){
//screenOnOffReceiver = new ScreenOffBroadCastReciever();
screenState = intent.getBooleanExtra("screen_state",screenOff);
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
if (screenState){
mServiceHandler.sendMessage(msg);
}
if(screenState == false){
Log.d("SCREEN ON OFF RECIEVER","screenON(onStartCommand)");
try {
mAccelRecorder.onStopButtonIsClicked(true);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d("GaitAuthenticationService", "Stop Recording data");
}
// }
return GaitAuthenticationService.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
Log.i(" GaitAuthenticationService", "Service is destroyed");
if(screenOnOffReceiver!=null){
Log.i("screenreciever", "true");
unregisterReceiver(screenOnOffReceiver);
screenOnOffReceiver=null;
}
super.onDestroy();
}
/* (non-Javadoc)
* #see android.app.Service#onUnbind(android.content.Intaent)
*/
#Override
public boolean onUnbind(Intent intent) {
if(screenOnOffReceiver!=null){
Log.i("screenreciever", "true");
unregisterReceiver(screenOnOffReceiver);
screenOnOffReceiver = null;
}
return super.onUnbind(intent);
}
}
Here is my broadcast Reciever
public class ScreenOffBroadCastReciever extends BroadcastReceiver {
private boolean screenOff;
#Override
public void onReceive(Context context, Intent intent) {
if(intent!=null){
if ((intent.getAction().equals(Intent.ACTION_SCREEN_OFF))) {
screenOff = true;
}
if(intent.getAction().equals(Intent.ACTION_SCREEN_ON)){
screenOff = false;
}
Intent i = new Intent(context, GaitAuthenticationService.class);
i.putExtra("screen_state", screenOff);
context.startService(i);
}
}
}
Receiver in AndroidManifest.xml
<receiver android:name="ScreenOffBroadCastReciever" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>
</receiver>
Related
I have a Service in my app with which I send requests to a server. After I send a request to start an operation on the server, I need to poll the server for updates by sending a request every 15 seconds to track the progress. For this I use a ScheduledExecutorService that calls a Runnable.
The Service does a bunch of things in onHandleIntent and then starts the ScheduledExecutorService that does the polling. All of this is working fine.
The issue is while the ScheduledExecutorService is executing the Runnable at intervals, the service gets destroyed, as in the onDestroy method is called. Is there a way to prevent this from happening?
I have a Broadcast Receiver registered in the service that can be triggered any time by the user while the ScheduledExecutorService is executing the Runnable. But since the Service is destroyed, the Receiver gets unregistered.
Here is some simplified code:
#Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "OnHandleIntent started");
try {
if (intent != null) {
final String action = intent.getAction();
if (getActionUpload().equals(action)) {
wakeLock.acquire();
notificationConfig = new CustomNotificationConfig();
//Register receiver to stop operation
IntentFilter filter = new IntentFilter(ThirdPartyStopReceiver.ACTION_STOP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
mThirdPartyStopReceiver = new ThirdPartyStopReceiver();
registerReceiver(mThirdPartyStopReceiver, filter);
Boolean operationStarted = startOperation();
if (operationStarted) {
checkProgressAtIntervals();
}
}
}
} catch (Exception e) {
Log.e(TAG, "Error with XML");
e.printStackTrace();
} finally {
wakeLock.release();
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
try {
//Unregister the receiver
unregisterReceiver(mThirdPartyStopReceiver);
} catch (IllegalArgumentException e) {
//Receiver has already been unregistered. Do nothing
e.printStackTrace();
}
}
private void checkProgressAtIntervals() {
Log.d(TAG,"in checkProgressAtIntervals");
final ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
try {
int progress = sendProgressRequest();
if(isCanceled){
sendCancelRequest();
ses.shutdown(); //Stop polling
}
if (progress >= 100) {
ses.shutdown(); //Stop polling
}
} catch (Exception e) {
Log.e(TAG, "Exception in sendProgressRequest ");
e.printStackTrace();
}
}
}, 1, 15, TimeUnit.SECONDS);
}
public class ThirdPartyStopReceiver extends BroadcastReceiver {
public static final String ACTION_STOP = "thirdpartystop";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Cancel request received in onReceive");
isCanceled = true;
//...
}
}
So as you can see, I need to execute some code in the service if a "Stop" broadcast is received.
I have tried using a Handler with its postDelayed method but the service gets destroyed before the Handler starts to execute so the Runnable never executes. I tried instantiating the Handler with Looper.myLooper() but with the same result.
Since the runnable contains HTTP calls, instantiating Handler with Looper.getMainLooper() throws a NetworkOnMainThreadException
It seems you are using an IntentService, which stops after it ends its work, that is, the onHandleIntent method. An IntentService is intended to be short-lived.
Try using a regular Service instead. Mind that Android can stop a Service at its own discretion, but in a general manner the Service will run for a long period.
I want to check some web API and do something per x minutes. I think I should write a service on Android (is there any other solution?).
But how can do that?
I am thinking about writing a service class and in the manifest file I should add this line:
<service
android:name="com.xx.yy.noti_check"
android:enabled="true"
>
</service>
And in my noti_check class I check my web API like this on onStartCommand:
public class noti_check extends Service {
Context mcont;
private Handler myhandler ;
private long RETRY_TIME = 15000;
private long START_TIME = 2000;
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onStart(Intent intent, int startId) {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mcont=this;
myhandler= new Handler();
myhandler.postDelayed(myRunnable, START_TIME);
return Service.START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
try {
myhandler.removeCallbacks(myRunnable);
}
catch (Exception e) {
// TODO: handle exception
}
}
private Runnable myRunnable = new Runnable() {
public void run() {
try {
new get_notifyalert(mcont).execute("") ;
}
catch (Exception e) {
// TODO: handle exception
}
myhandler.postDelayed(myRunnable, RETRY_TIME);
}
};
}
Is this is the right way?
Is this the right way?
No. Only have a service running when it is actively delivering value to the user. Watching the clock tick is not actively delivering value to the user. Use AlarmManager for periodic work like this.
In my app i am using a Service that periodically checks if there is a new personal message for the logged in user.
The service is started if the user enables the notification feature. Now if the user disables the notification feature i would like to stop the service.
I try to stop the service with the following lines of code.
Intent service = new Intent(getApplicationContext(), MessageService.class);
stopService(service);
The problem is that the service doesn't stop. It goes on working.
Here you can see my message service.
public class MessageService extends Service {
private int intervall;
public MessageService(){
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent,flags,startId);
Bundle intentData = intent.getExtras();
if(intentData != null) {
this.intervall = intentData.getInt("intervall");
}
final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// async task for calling api otherwise we get an exeception here
new ServiceMessagesTask().execute(MessageService.this);
}
};
new Thread(new Runnable(){
public void run() {
while(true)
{
try {
Thread.sleep(intervall); // repeat after given intervall
handler.sendEmptyMessage(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
I have an activity where the user can edit his preferences. There it is also possible to activate the notification feature.
The notification service is started or stoped in the savePreferences() method:
public void savePreferences(View button) {
EditText login = (EditText)findViewById(R.id.txtbLogin);
EditText password = (EditText)findViewById(R.id.txtbPassword);
CheckBox enableNotification = (CheckBox) findViewById(R.id.cbNotifications);
Spinner spinner = (Spinner) findViewById(R.id.notificationInterval);
if(!login.getText().equals("") && !password.getText().equals("")){
Map<String, Object> preferences = new HashMap<String, Object>();
preferences.put("document_type", CouchbaseHelper.CB_VIEW_USER_PREFERENCES);
preferences.put("login", login.getText().toString());
preferences.put("password", password.getText().toString());
if(enableNotification.isChecked()){
preferences.put("enableNotification", true);
} else {
preferences.put("enableNotification", false);
}
preferences.put("notificationInterval", this.notificationInterval);
CouchbaseHelper couchbaseHelper = new CouchbaseHelper(getApplicationContext());
String documentId = couchbaseHelper.createDocUserPreferences(preferences);
couchbaseHelper.closeDb();
// start notification service if enabled
if(enableNotification.isChecked()){
Intent service = new Intent(getApplicationContext(), MessageService.class);
service.putExtra("intervall", Integer.valueOf(this.notificationInterval)*60*1000);
startService(service);
} else {
// TODO: this is not working!!! service doesnt stop
// try to stop running service
if(isMyServiceRunning()){
Intent service = new Intent(getApplicationContext(), MessageService.class);
stopService(service);
}
}
}
finish();
Intent main = new Intent(Preferences.this, Main.class);
startActivity(main);
}
I'm afraid you really don't get what a service is, service is just a component that do not require UI and is not linked to an activity life cycle, hence it runs in background, BUT background doesn't necessarily means in a separate thread, actually the service runs in the main thread, now that's one thing, killing a service doesn't mean you are killing all the working threads you create within, and in your code you are creating a Thread that is looping forever, that thread although created in the service is not linked in any way to the service life cycle.
So, if you want to stop the thread, get a reference to the thread you are creating in the startCommand method and in the onDestroy method just stop it, instead of having a while(true) validation, go for a flag and just change it to false in the onDestroy so it will stop the thread you created when started the service.
Regards!
I want to call a service which repeatedly queries a Parse.com database and monitors a specific attribute.Here's what Ive got so far:
public class Battle extends Service {
#Override
public int onStartCommand(Intent intent,int flags,int startId)
{
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
ParseUser currentUser = ParseUser.getCurrentUser();
username = currentUser.getString("username");
findinBackground();
return START_STICKY;
}
private void findinBackground(){
//public void run() {
// TODO Auto-generated method stub
while(true)
{
query = ParseUser.getQuery();
query.whereEqualTo("isAttacking", username);
query.findInBackground(new FindCallback<ParseUser>() {
public void done(List<ParseUser> objects, ParseException e) {
if ((e == null)&(objects.size() != 0))
{
// The query was successful.
ParseUser attacker = objects.get(0);
String attackerName = attacker.getUsername();
Log.i("ambustest",attackerName);
makeToast(attackerName);
}
else
{
Log.i("fd","Something went wrong.");
}
}
});
}
}
}
This code compiles fine but stops responding at runtime.Here's my logcat:
You need to call the service on a separate thread
#Override
public int onStartCommand(Intent intent,int flags,int startId)
{
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
ParseUser currentUser = ParseUser.getCurrentUser();
username = currentUser.getString("username");
new Thread()
{
public void run() {
findinBackground();
}
}.start();
return START_STICKY;
}
It should be noted that Intent Service is automatically called on a separate thread, however a regular service is not.
Services are run on the same thread as your UI. If you want to do time consuming operations, you need to fire them off in a separate thread.
The best solution is a Remote Service with a Handler that reports your client(s) (Activity) about changes.
http://developer.android.com/reference/android/app/Service.html
Your Service will run in a seperate process
First you need a AIDL - as an interface to communicate with service and client
// IRemoteService.aidl
package de.contecon.android.util.abstractservice;
interface IRemoteService {
void registerCallback(IRemoteServiceCallback mCallback);
void unregisterCallback(IRemoteServiceCallback mCallback);
}
Your Service can look like this
//RemoteService.java
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY_COMPATIBILITY;
}
#Override
public void onCreate() {
// While this service is running, it will continually increment a
// number. Send the first message that is used to perform the
// increment.
mHandler.sendEmptyMessage(REPORT_MSG);
}
#Override
public IBinder onBind(Intent intent) {
// Select the interface to return. If your service only implements
// a single interface, you can just return it here without checking
// the Intent.
if (IRemoteService.class.getName().equals(intent.getAction())) {
return mBinder;
}
//Example for a second Binder
// if (IRemoteServiceSecondary.class.getName().equals(intent.getAction())) {
// return mBinderSec;
// }
return null;
}
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
#Override
public void registerCallback(IRemoteServiceCallback mCallback) throws RemoteException {
if (mCallback != null) mCallbacks.register(mCallback);
}
#Override
public void unregisterCallback(IRemoteServiceCallback mCallback) throws RemoteException {
if (mCallback != null) mCallbacks.unregister(mCallback);
}
};
/**
* Our Handler used to execute operations on the main thread. This is used
* to schedule increments of our value.
*/
private final Handler mHandler = new Handler() {
#Override public void handleMessage(Message msg) {
switch (msg.what) {
// It is time to bump the value!
case REPORT_MSG: {
// Up it goes.
int value = ++mValue;
// Broadcast to all clients the new value.
final int N = mCallbacks.beginBroadcast();
for (int i=0; i<N; i++) {
try {
mCallbacks.getBroadcastItem(i).valueChanged(value);
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
mCallbacks.finishBroadcast();
// Repeat every 1 second.
sendMessageDelayed(obtainMessage(REPORT_MSG), 1*1000);
} break;
default:
super.handleMessage(msg);
}
}
};
And your Client
/**
* This implementation is used to receive callbacks from the remote
* service.
*/
private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
/**
* This is called by the remote service regularly to tell us about
* new values. Note that IPC calls are dispatched through a thread
* pool running in each process, so the code executing here will
* NOT be running in our main thread like most other things -- so,
* to update the UI, we need to use a Handler to hop over there.
*/
public void valueChanged(int value) {
mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value, 0));
}
};
private static final int BUMP_MSG = 1;
private Handler mHandler = new Handler() {
#Override public void handleMessage(Message msg) {
switch (msg.what) {
case BUMP_MSG:
mCallbackText.setText("Received from service: " + msg.arg1);
break;
default:
super.handleMessage(msg);
}
}
};
public void startService() {
// Make sure the service is started. It will continue running
// until someone calls stopService().
// We use an action code here, instead of explictly supplying
// the component name, so that other packages can replace
// the service.
startService(new Intent(
"your.action.uri.code.REMOTE_SERVICE"));
}
public void stopService() {
// Cancel a previous call to startService(). Note that the
// service will not actually stop at this point if there are
// still bound clients.
stopService(new Intent(
"your.action.uri.code.REMOTE_SERVICE"));
}
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. We are communicating with our
// service through an IDL interface, so get a client-side
// representation of that from the raw service object.
mService = IRemoteService.Stub.asInterface(service);
mCallbackText.setText("Attached.");
// We want to monitor the service for as long as we are
// connected to it.
try {
mService.registerCallback(mCallback);
} catch (RemoteException e) {
// In this case the service has crashed before we could even
// do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here.
}
// As part of the sample, tell the user what happened.
Toast.makeText(RemoteServiceBinding.this, "service connected",
Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mCallbackText.setText("Disconnected.");
// As part of the sample, tell the user what happened.
Toast.makeText(RemoteServiceBinding.this,"service disconnected",
Toast.LENGTH_SHORT).show();
}
};
private void bindService(){
// Establish a couple connections with the service, binding
// by interface names. This allows other applications to be
// installed that replace the remote service by implementing
// the same interface.
bindService(new Intent(IRemoteService.class.getName()),
mConnection, Context.BIND_AUTO_CREATE);
bindService(new Intent(IRemoteServiceSecondary.class.getName()),
mSecondaryConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
mCallbackText.setText("RemoteServiceBinding.");
}
private void unbindService(){
if (mIsBound) {
// If we have received the service, and hence registered with
// it, then now is the time to unregister.
if (mService != null) {
try {
mService.unregisterCallback(mCallback);
} catch (RemoteException e) {
// There is nothing special we need to do if the service
// has crashed.
}
}
// Detach our existing connection.
unbindService(mConnection);
unbindService(mSecondaryConnection);
mIsBound = false;
mCallbackText.setText("Unbinding.");
}
}
AndroidManifest.xml
<service
android:name=".service.RemoteService"
android:process=":remote"
android:enabled="true" >
<intent-filter>
<!-- These are the interfaces supported by the service, which
you can bind to. -->
<action android:name="de.your.path.util.abstractservice.IRemoteService" />
<!-- This is an action code you can use to select the service
without explicitly supplying the implementation class. -->
<action android:name="your.action.uri.code.REMOTE_SERVICE" />
</intent-filter>
</service>
the service is started by a single activity 4 times, how many threads are created by a service? And if service is started by 4 different activities then how many threads are created? Which function must be implemented inside a service inherited from intentService? how many threads are required to create inside this function?
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
the service is started by a single activity 4 times, how many threads are created by a service?
Depends. Your Service creates a new thread in onCreate, so if it's never killed then you'll only have 1 thread created. If somehow it did get killed, you would end up with one for every time you started your Service.
And if service is started by 4 different activities then how many threads are created?
Same as above.
Which function must be implemented inside a service inherited from intentService?
You might try reading the docs for IntentService, you'd find you want to implement onHandleIntent.
how many threads are required to create inside this function?
Zero.