I am currently writing a android program which needs an IntentService. When I put the code in the onHandleIntent function, the code does not run, but it doesn't give errors in the MainActivity. But when I copy my code into the onStartCommand, it runs perfectly.
The problem is that I wanna know what are the differences between onHandleIntent and onStartCommand. Thanks.
CODE:
In onHandleIntent:
System.out.println("SERVICE STARTED! ! !");
//System.out.println(intent.getBooleanExtra("once", Boolean.FALSE));
if (intent.getBooleanExtra("once", Boolean.FALSE)) {
Check();
}
mHandler.postDelayed(mRunnable, 3000);
As from the docs:
The IntentService does the following:
Creates a default worker thread that executes all intents delivered to onStartCommand() separate from your application's main thread.
Creates a work queue that passes one intent at a time to your onHandleIntent() implementation, so you never have to worry about
multi-threading.
Stops the service after all start requests have been handled, so you never have to call stopSelf().
Provides default implementation of onBind() that returns null.
Provides a default implementation of onStartCommand() that sends the intent to the work queue and then to your onHandleIntent()
implementation.
And also:
All this adds up to the fact that all you need to do is implement
onHandleIntent() to do the work provided by the client. (Though, you
also need to provide a small constructor for the service.)
So an IntentService is a "Custom" Service with those special properties. So there's no need to override the onStartCommand(), actually, you shouldn't do it unless you're using the regular Service class.
Some example of IntentService usage:
Activity.java
Intent it = new Intent(getApplicationContext(), YourIntentService.class);
it.putExtra("Key", "Value");
startService(it);
YourIntentService.java
public YourIntentService() {
super("YourIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
String str = intent.getStringExtra("key");
// Do whatever you need to do here.
}
//...
}
You can also check this tutorial or this one for more info about Service and IntentService.
Also, check the docs.
onStartCommand() is used when you use a Service. onHandleIntent() should be used instead when you use an IntentService. IntentService extends Service. And as per documentation
"You should not override this method(onStartCommand) for your
IntentService. Instead, override onHandleIntent(Intent), which the
system calls when the IntentService receives a start request."
If you have overridden onStartCommand(), that might be why your onHandleIntent() is not getting called.
You should not override onStartCommand() for your IntentService.
If you do, make sure to return super.onStartCommand(); because that sends the Intent to the work queue and then to your onHandleIntent() implementation.
Related
I am trying to understand the Service Life Cycle while working through some Android Open Source Code.
I was looking at a Service implementation which I distilled down to something like the following...
public class MyService extends Service {
public MyService() { super(); }
#Override
public void onCreate() {
super.onCreate();
init();
//==this seems odd to me
//comment in AOSP says startService() is called to make
//sure Service stays around long enough for the async call
//to complete.
startService(new Intent(this, myservice.class()));
doSomeMoreInitAsync();
}
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
if(actionableIntent(intent,flags,startId)) {
//do something
//NOTE: the Intent passed to startService() in onCreate()
//above will go around this block of code, doing nothing
//except returning START_STICKY
}
return START_STICKY;
}
public void onDestroy() {
//destroy stuff
}
#Override
public IBinder onBind(final Intent intent) {
return mBinder; //an instance of android.os.Binder derivative
// created when this service was instantiated
}
//other stuff
}
Why would someone want to have onCreate() call startService() on itself like above, doing nothing? The comment in code sheds some light, but it's like assumptions are being made about the Life Cycle that I don't understand. I.e., is it reasonable to expect onCreate() to effectively start its own service?
I know that if a service has already been started then onCreate() will only be called once (unless destroyed and restarted, then a new instance of the service is created and onCreate() is called once on it). My first concern with this example would be that there is an expectation placed upon the underlying Service API implementation that the Service is already in the initialized state before onCreate() is called (else there be an infinite recursion, but there is not).
But isn't onCreate() supposed to be part of the initialization (albeit an optional part for the subclass)?
Is this coding logic a reasonable way of making sure the Service is forced to be an Unbounded Service? Or am I looking at a bad example in the AOSP which may have undefined behavior in the future?
You are correct in that a Service will call onCreate and onStartCommand if it is started via Context.startService. So in this sense, when you return START_STICKY, the Service will continually run until an explicit call to stopService() is called. It will also be destroyed and restarted during this lifecycle.
Another way to create a Service, is by binding to it. As per the docs:
Clients can also use Context.bindService() to obtain a persistent connection to a service. This likewise creates the service if it is not already running (calling onCreate() while doing so), but does not call onStartCommand().
So, it's possible for a Service to be created by simply binding to it. However, the lifecycle of a Service indicates that it will remain if it is started or a client is still bound to it. Meaning, that if it was created by a bind command, it will immediately be destroyed as soon as the client unbinds.
So, if a Service starts itself in the onCreate(), it will ensure that it puts itself in the started state regardless of whether it was created by binding or by an explicit call to startService. Since there's no actionable intent, the onStartCommand will just pass straight through. An clients that call startSevice will, presumably, have actionable Intents in which case the Service will perform its duties.
My Android application is activating a service that call an 'Activity.
On mainActivity:
startService(new Intent(getBaseContext(),MyService.class));
And then on service:
public int onStartCommand(Intent intent,int flage,int startId){
// Toast.makeText(this, "Yes please", Toast.LENGTH_LONG).show();
Intent mIntent=new Intent(MyService.this,trackingActivity.class);
mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(mIntent);
return START_STICKY; }
At the end of trackingActivity this line is written (Again):
startService(new Intent(getBaseContext(),MyService.class));
That's creates a lot of Services. Is there a better way to create a background service that repeats itself always without creating each time a new Service ?
I tried to do a while loop inside the Activity :
while(true){
Actions on activity
}
But with no success.
Context.startService(Intent) does not create a new Service for each call.
If there is already a matching service running, it passes the intent to that running service, but does not create a new one each time.
See the Android Developer Docs for Context.startService(Intent):
If this service is not already running, it will be instantiated and
started (creating a process for it if needed); if it is running then
it remains running.
Every call to this method will result in a corresponding call to the target service's onStartCommand(Intent, int, int) method, with the intent given here.
There is similar information in the Android Developer Docs about Starting a Service:
[When starting a service using an intent] the startService() method returns immediately and the Android system
calls the service's onStartCommand() method. If the service is not
already running, the system first calls onCreate(), then calls
onStartCommand().
...
Multiple requests to start the service result in multiple
corresponding calls to the service's onStartCommand(). However, only
one request to stop the service (with stopSelf() or stopService()) is
required to stop it.
How do I run a parallel action (process) to the main app in Android?
I know that, there are a lot of ways to do it: Threads, Tasks, Handlers and etc'...
This is the way I chose. But I think it takes a lot of memory and doesn't closes in the interrupt call.
checkReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO: Check is this a good way to handle threads
Thread t = new Thread() {
#Override
public void run() {
internetConnectionManager.TryConnect();
this.interrupt();
}
};
t.start();
}
}
};
Two things wrong with your arroach:
You should not start a thread in onRecieve method. The reason is explained here :
This has important repercussions to what you can do in an
onReceive(Context, Intent) implementation: anything that requires
asynchronous operation is not available, because you will need to
return from the function to handle the asynchronous operation, but at
that point the BroadcastReceiver is no longer active and thus the
system is free to kill its process before the asynchronous operation
completes
Second, calling Thread.currentThread().interrupt() does not make any sense in your example since your thread is already done by that line and will finish, and also because you don not check interrupted flag anyway.
The better way, in my opinion, would be to start a simple IntentService from your onReceive code. Here is a simple tutorial.
Important edit based on FunkTheMonk's comment:
If the broadcast comes from an alarm or external event, it is possible that your device will go to sleep shortly after onReceive returns (even if you create a service). If that is the case, instead of using regular BroadCastReceiver you should extend WakefulBroadcastReceiver from support library.
Use handler
if you want to stop handler then fire an intent with some value eg.("quit handler")to receiver
and call remove call back and inside handler you can handle the rest using ACTION switch
you can also use intentservice
I have a android Service, in the onStart method i get many Strings from the Intent activity, and then execute a AsynTask to download files from internet.
When the activity is running this works ok, but when i stop the activity, this relaunch the onStart method, but obiusly the intent is null causing me nullPointerException.
What can i do the service dont entry on onStart, and continues the first asyntask to download all the files?
This is my code
#Override
public void onStart(Intent intent, int startId) {
desde = intent.getIntExtra("desde", 0);
hasta = intent.getIntExtra("hasta", 1);
email = intent.getStringExtra("email");
password = intent.getStringExtra("password");
new DescargaFotos().execute();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
and in Inicio.java (The UI activity)
Intent iService = new Intent(contexto,
ServiceDownloader.class);
iService.putExtra("desde", 0);
iService.putExtra("hasta", 5);
iService.putExtra("email", email);
iService.putExtra("password", password);
startService(iService);
EDIT:
New question:
I am using IntentService and i bind the service like this:
Intent iService = new Intent(contexto,
ServiceDownloader.class);
ServiceConnection serviceConector = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
Log.i("INFO", "Service bound ");
}
#Override
public void onServiceConnected(ComponentName name,
IBinder service) {
Log.i("INFO", "Service Unbound ");
}
};
iService.putExtra("desde", 0);
iService.putExtra("hasta", 50);
iService.putExtra("email", email);
iService.putExtra("password", password);
startService(iService);
bindService(iService, serviceConector,
Context.BIND_AUTO_CREATE);
And now my problem is, in my galaxy nexus, if i enter in app runtime list, and destroy my app, the service stopped, and stop donwload, stop send notification etc? How must i bind the service to solve this?
Use an IntentService. IntentService is specifically designed to do what you want. You don't have to implement onStart, onStartCommand, etc. The work runs on a background thread. Once the work finishes, the Thread is destroyed.
IntentService will continue to run regardless of the state of the Activity.
One problem you may have is that you're sending out your Intent in the wrong place in your Activity, or you're not checking to see if the operation is complete. Before you send the Intent, check a flag in SharedPreferences (if the flag doesn't exist, it means you're starting for the first time). When you send the Intent, store a flag in SharedPreferences to indicate that you sent it. When your IntentService receives the Intent, have it update the flag to say it received it. Before the IntentService finishes, have it update the flag again. And so forth.
I do not have reputation to comment your question, so I will write a answer :)
First off all, in my opinion, if your Service do just this, get some string and download files from the Internet, you do not need the service. The AsyncTaks is enough to solve your problem and it is more simple to implement. Doing that, you avoid the problem with your intent.
From Android API:
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
However, if you decide to continue using a service, lt me know exactly when startService is called in your activity.
If you have some doubt about when use AsyncTask, Service, IntentService and Thread, this link can help you.
This would be my suggestion...
Use a thread in the service rather then AsyncTask since AsynTask should only be used small task. Check following statement from AsyncTask javadoc:
AsyncTask is designed to be a helper class around Thread and Handler
and does not constitute a generic threading framework. AsyncTasks
should ideally be used for short operations (a few seconds at the
most.) If you need to keep threads running for long periods of time,
it is highly recommended you use the various APIs provided by the
java.util.concurrent pacakge such as Executor, ThreadPoolExecutor and
FutureTask.
So from your on start check the status of your thread, if it is running then don't do anything, if it is not running then start the thread that would download your images...
I am able to stop my ServiceA(it is started using AlarmManager) when an IntentService is running by sending a broadcast from IntentService to broadcast receiver. I want to Start the same ServiceA again after my IntentService finished his work.
Ex-I have Service SrvA,IntentService IntSrvB and BroadcastReceiver MyBcr.When my IntSrvB running i am able to stop SrvA.My problem is How to Restart SrvA again when my IntSrvB finish his work.
Note-ServA is started using AlarmManager.
EDIT: Based on your code, you can pass your variables myIntent & myIntent2 into your IntentService class - you can then use them to recreate exact replicas of the pending intents used with the AlarmManager.
Please note that it looks like you set an Alarm for each intent that repeats once "NOW" and then at intervals after that. You then implicitly start the service again i.e. you start the service twice "NOW". That looks like a mistake - look at the docs for the AlarmManager.setRepeating() method.
Original answer below...
Put this into your IntentService:
#Override
protected void onHandleIntent(Intent intent)
{
try
{
// STOP SERVICE
// DO YOUR WORK HERE
}
finally
{
// START SERVICE
}
}
You already have the code to stop the service. You can take the "start service" code from your BroadcastReceiver and put it in the finally block.
I would not recommend overriding onDestroy() in general on Android.
NOTE: I don't think this is the best way to design your app, but I'm answering your question. Personally, I would have a method in my main Service that is able to disable & enable its functionality - and then call that method instead of starting & stopping the service.