To know the difference between IntentService and Service in Android, I created the below posted small test of an IntentService class. The IntentService class can be started using
startService(intent); which will result in a call to nStartCommand(Intent intent, int flags, int startId). Also to send values from the IntentService class to the MainActivity
for an example, we should send it via sendBroadcast(intent); and the MainActivity should register a broadcastReceiver for that action so it can receive the values sent via
sendBroadcast(intent);
so far I cant see any difference between Service and IntentService!! Since they are similar in the way of starting them and the way they broadcast data,can you please tell me in
which context they differ?
please tell me why i am receiving those errors and how to solve it
MainActivity
public class MainActivity extends AppCompatActivity {
private final String TAG = this.getClass().getSimpleName();
private Button mbtnSend = null;
private int i = 0;
private BroadcastReceiver mBCR_VALUE_SENT = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(MyIntentService.INTENT_ACTION)) {
int intnetValue = intent.getIntExtra(MyIntentService.INTENT_KEY, -1);
Log.i(TAG, SubTag.bullet("mBCR_VALUE_SENT", "intnetValue: " + intnetValue));
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
registerReceiver(this.mBCR_VALUE_SENT, new IntentFilter(MyIntentService.INTENT_ACTION));
this.mbtnSend = (Button) findViewById(R.id.btn_send);
this.mbtnSend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), MyIntentService.class);
intent.putExtra("intent_key", ++i);
startService(intent);
}
});
}
}
MyIntentService:
public class MyIntentService extends IntentService {
private final String TAG = this.getClass().getSimpleName();
public final static String INTENT_ACTION = "ACTION_VALUE_SENT";
public final static String INTENT_KEY = "INTENT_KEY";
public MyIntentService() {
super(null);
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* #param name Used to name the worker thread, important only for debugging.
*/
public MyIntentService(String name) {
super(name);
setIntentRedelivery(true);
}
#Override
public void onCreate() {
super.onCreate();
Log.w(TAG, SubTag.msg("onCreate"));
}
#Override
protected void onHandleIntent(Intent intent) {
Log.w(TAG, SubTag.msg("onHandleIntent"));
int intent_value = intent.getIntExtra("intent_key", -1);
Log.i(TAG, SubTag.bullet("", "intent_value: " + intent_value));
Intent intent2 = new Intent();
intent2.setAction(MyIntentService.INTENT_ACTION);
intent2.putExtra(MyIntentService.INTENT_KEY, intent_value);
sendBroadcast(intent2);
SystemClock.sleep(3000);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.w(TAG, SubTag.msg("onStartCommand"));
return super.onStartCommand(intent, flags, startId);
}
In short, a Service is a broader implementation for the developer to set up background operations, while an IntentService is useful for "fire and forget" operations, taking care of background Thread creation and cleanup.
From the docs:
Service A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.
IntentService Service is a base class for IntentService Services that handle asynchronous requests (expressed as Intents) on demand. 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.
Refer this doc - http://developer.android.com/reference/android/app/IntentService.html
Service
This is the base class for all services. When you extend this class, it’s important that you create a new thread in which to do all the service’s work, because the service uses your application’s main thread, by default, which could slow the performance of any activity your application is running.
IntentService
This is a subclass of Service that uses a worker thread to handle all start requests, one at a time. This is the best option if you don’t require that your service handle multiple requests simultaneously. All you need to do is implement onHandleIntent(), which receives the intent for each start request so you can do the background work.
Below are some key differences between Service and IntentService in Android.
1) When to use?
The Service can be used in tasks with no UI, but shouldn’t be too long. If you need to perform long tasks, you must use threads within Service.
The IntentService can be used in long tasks usually with no communication to Main Thread. If communication is required, can use Main Thread handler or broadcast intents. Another case of use is when callbacks are needed (Intent triggered tasks).
2) How to trigger?
The Service is triggered calling to method onStartService().
The IntentService is triggered using an Intent, it spawns a new worker thread and the method onHandleIntent() is called on this thread.
for more clarity refer this
http://www.onsandroid.com/2011/12/difference-between-android.html
Related
I have an activity and it shows progress dialog when the user starts download
And the download from ftp start in a service
I want to dismiss this progress dialog when the service finishes downloading file
How to dismiss it from service?
A better approach would be to use LocalBroadcastManager for notifying Activity from Service.
Step1: Send the local broadcast from your service
public class MyService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// do your operation here(create worker thread for blocking operations)
sendLocalBroadCast() //call this method as soon as above operations completes
return Service.START_NOT_STICKY;
}
}
private void sendLocalBroadCast() {
Intent intent = new Intent("MY_SERVICE_NOTIFICATION");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
Note that the system calls onStartCommand(Intent intent, int flags, int startId) on your service's main thread. A
service's main thread is the same thread where UI operations take
place for Activities running in the same process. You should always
avoid stalling the main thread's event loop. When doing long-running
operations, network calls, or heavy disk I/O, you should kick off a
new thread, or use AsyncTask
Step2: Make your Activity listen to this broadcast
public class MyActivity extends Activity{
BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// you can dismiss your progress dialog here. This method will be called when we receive broadcast from service after the service operation is completed
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
//register for listening to "MY_SERVICE_NOTIFICATION" event
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver,
new IntentFilter("MY_SERVICE_NOTIFICATION"));
}
#Override
protected void onDestroy() {
super.onDestroy();
// remove the receiver
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
}
}
Create an interface finishListener which has listen method, implement it in the activity to do whatever you want and pass it to the service constructor from there call listen method
Its simple
alertdialog.dismiss();
just put that in the bottom of your install code
I have a loop which do call to service:
context.startService(intent);
In and want to get back the result after the service finish its processing for each request. So I pass an unique id to intent to be able to distinguish the response.
But unfortunately, the startService which call to onStartCommand is not thread-safe. This leads to the response is always the last id, as the intent was changed in later call.
The service code is similar:
public class MyService extends Service {
protected Bundle rcvExtras;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
rcvExtras = intent.getExtras();
// Todo with information in rcv Extra
BaseRestClient restClient = new BaseRestClient(rcvExtras.getString(Constants.INTENT_KEY_OBJECT_TYPE));
restClient.post(data, rcvExtras.getString(Constants.INTENT_KEY_URL), new CallBackHandler(this)); // This is an async call
return super.onStartCommand(intent, flags, startId);
}
private class CallBackHandler extends Handler {
private final WeakReference<MyService> myServiceRef;
public CallBackHandler(MyService myService) {
myServiceRef = new WeakReference<>(myService);
}
#Override
public void handleMessage(Message msg) {
Intent result = new Intent(Constants.WS_CALL_BACK);
rcvExtras.putInt(Constants.INTENT_KEY_STATUS, msg.what);
result.putExtras(rcvExtras);
log.info("Broadcast data");
sendBroadcast(result); // Broadcast result, actually the caller will get this broadcast message.
MyService myService = myServiceRef.get();
log.info("Stopping service");
myService.stopSelf(startId);
}
}
}
How can I make service calling thread-safe?
I can see your problem, this is programatic issue not caused by framework. Here from you call startService until you call stopself, your MyService is singleton, and your rcvExtras is a global variable and will be shared between threads.
It is simple to fix:
Move the declaration of rcvExtras to method scope, here is onStartCommand.
Extend the CallBackHandler to allow your rcvExtras, and use it once callback.
At this time you do not have any varable can be shared, and you safe.
Hope this help.
I am having problem with my android IntentService. When I first open the application, the service gets started by intent from the profile activity and data is fetched from this service. If I switch to other activity and then back service is still running and that is ok.
However if you press back, so that activity is finished and put in the background, the service is still working as the application is in background but If I get it back to foreground service stops. I do not know why. Bellow is my code, please help.
I have read activity life cycle couple of times and still do not get it why this is happening.
What is weird is that Service receive data one more time before it stops when MainActivity is brought back to running state. Service is not crashing.
Service
public class SomeService extends IntentService
{
public static final String extra = "someData";
public SomeService()
{
super(SomeService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent)
{
Log.e("SomeService", "starting service");
while (true)
{
SomeData data = Api.getNewSocketData();
//Broadcast data when received to update the view
Intent broadcastData = new Intent();
broadcastData.setAction(dataBroadcastReceiver.ACTION_DATA_RECEIVED);
broadcastData.addCategory(Intent.CATEGORY_DEFAULT);
broadcastData.putExtra(extra, " ");
sendBroadcast(broadcastData);
Log.e("SomeService", "received from socket");
}
}
}
Receiver
public class dataBroadcastReceiver extends BroadcastReceiver
{
public final static String ACTION_DATA_RECEIVED = "net.bitstamp.intent.action.ACTION_SOMEDATA_RECEIVED";
#Override
public void onReceive(Context context, Intent intent)
{
Log.e("receiver", "data received");
}
}
Main Activity
#Override
public void onPause()
{
super.onPause();
unregisterReceiver(dataBroadcastReceiver);
}
#Override
public void onResume()
{
super.onResume();
IntentFilter intentFilter = new IntentFilter(dataBroadcastReceiver.ACTION_DATA_RECEIVED);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
dataBroadcastReceiver = new dataBroadcastReceiver();
registerReceiver(dataBroadcastReceiver, intentFilter);
Intent someService = new Intent(this, SomeService.class);
startService(someService);
}
I really need help on this. Thanks
You don't want to the up the IntentService in an infinite loop. It will block all other incoming requests. From the documentation:
All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.
Your Service is likely still happily running along, it just isn't processing your new request because your old one is still being handled in the infinite loop.
I'm designing my first Android app.
This app consist in several Runnable that do some stuff. Initially I made this Runnable to be execute by a Thread (a Thread for each Runnable). Each Runnable is also Observable, so it can notify changes to Activity. User click on a start button, one or more Runnable starts, them do their job notifying gui during execution and then stops. All works fine.
First question: Is that approach the right one? In order to answer this question please keep reading.
I need two other things in my app:
to be sure that execution of my jobs doesn't stops, even if user goes away from my app to do something else;
to plan the execution of my Runnable that has to start and execute in background. Example: user decides that wants a "job" to be execute everyday at 16:00.
I've seen that I can do that with an AlarmManager and Service.
Second question: I need a Service that can manage several Runnable asynchronously, so when AlarmManager starts I ask this Service to do the requested job; I'll also modify the first part of application: instead of Thread I'll use this Service, so I can be sure that execution doesn't stop.
What kind of Service I need? IntentService can do this job?
It's right to proceed in this way? There is a better solution?
Can you give me some example of how I can implement all that?
I hope that I explained clearly my situation, otherwise I'll try to do it better.
Regards
First question: Is that approach the right one?
No, you should implement and run your Runnables in Threads in a Service.
An IntentService would be your best option if you don't require your Service to handle multiple requests simultaneously. If you start a Service it will keep running in the background even if the Activity that started it goes to the background or stops.
A Runnables can send a broadcast indicating a UI update is needed. The Activity should register a BroadcastReceiver to listen to the broadcast message and update the UI accordingly.
You can use an AlarmManager to schedule the execution of your jobs as you indicated. One way to do it is to schedule the AlarmManager to send a broadcast to be received by your IntentService which acts upon it by running the appropriate job.
Here is an example that combines all that:
Here is the IntentService
public class MyIntentService extends IntentService {
public static final String ACTION_START_JOB = "com.mycompany.myapplication.START_JOB";
public static final String ACTION_UPDATE_UI = "com.mycompany.myapplication.UPDATE_UI";
private final IBinder mBinder = new MyBinder();
// You can have as many Runnables as you want.
Runnable run = new Runnable() {
#Override
public void run() {
// Code to run in this Runnable.
// If the code needs to notify an Activity
// for a UI update, it will send a broadcast.
Intent intent = new Intent(ACTION_UPDATE_UI);
sendBroadcast(intent);
}
};
public MyIntentService() {
super("MyIntentService");
}
#Override
public void onCreate() {
// You need to register your BroadcastReceiver to listen
// to broadcasts made by the AlarmManager.
// The BroadcastReceiver will fire up your jobs when these
// broadcasts are received.
IntentFilter filter = new IntentFilter(ACTION_START_JOB);
registerReceiver(jobBroadcastReceiver, filter);
}
#Override
public void onDestroy() {
// You should unregister the BroadcastReceiver when
// the Service is destroyed because it's not needed
// any more.
unregisterReceiver(jobBroadcastReceiver);
}
/**
* This method is called every time you start this service from your
* Activity. You can Spawn as many threads with Runnables as you want here.
* Keep in mind that your system have limited resources though.
*/
#Override
protected void onHandleIntent(Intent intent) {
Intent intentFireUp = new Intent();
intentFireUp.setAction(ACTION_START_JOB);
PendingIntent pendingIntentFireUpRecording = PendingIntent
.getBroadcast(MyIntentService.this, 0, intentFireUp, 0);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar cal = Calendar.getInstance();
int year = 2013, month = 5, day = 10, hourOfDay = 7, minute = 13, second = 0;
cal.set(year, month, day, hourOfDay, minute, second);
long startTime = cal.getTimeInMillis() + 5 * 60 * 1000; // starts 5
// minutes from
// now
long intervalMillis = 24 * 60 * 60 * 1000; // Repeat interval is 24
// hours (in milliseconds)
// This alarm will send a broadcast with the ACTION_START_JOB action
// daily
// starting at the given date above.
alarm.setRepeating(AlarmManager.RTC_WAKEUP, startTime, intervalMillis,
pendingIntentFireUpRecording);
// Here we spawn one Thread with a Runnable.
// You can spawn as many threads as you want.
// Don't overload your system though.
new Thread(run).run();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// Depending on your implementation, you may need to bind
// to this Service to run one of its methods or access
// some of its fields. In that case, you will need a Binder
// like this one.
public class MyBinder extends Binder {
MyIntentService getService() {
return MyIntentService.this;
}
}
// Spawns a Thread with Runnable run when a broadcast message is received.
// You may need different BroadcastReceivers that fire up different jobs.
BroadcastReceiver jobBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
new Thread(run).run();
}
};
}
And here is the Activity
public class MyActivity extends Activity {
Service mService;
boolean mBound = false;
ToggleButton mButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (ToggleButton) findViewById(R.id.recordStartStop);
mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mButton.isChecked()) {
Intent intent = new Intent(MyActivity.this,
MyIntentService.class);
startService(intent);
}
}
});
}
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter(MyIntentService.ACTION_UPDATE_UI);
registerReceiver(uiUpdateBroadcastReceiver, filter);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(uiUpdateBroadcastReceiver);
}
BroadcastReceiver uiUpdateBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Here goes the code to update your User Interface
}
};
ServiceConnection myServiceConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
mBound = false;
}
// If you need
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyIntentService mService = ((MyBinder) service).getService();
mBound = true;
}
};
}
And don't forget to add the Service definition in your AndroidManifest.xml file:
<manifest ... >
...
<application ... >
<service android:name=".MyIntentService" />
...
</application>
</manifest>
I'm trying to understand the IntentService class so that I can build my own extension in which I can block the queue the handles all the threads whenever I want. The code below has been copied from here: http://www.google.com/codesearch#cZwlSNS7aEw/frameworks/base/core/java/android/app/IntentService.java&q=IntentService&exact_package=android&type=cs
In my main Activity I have the following code:
Intent intent = new Intent(this,DownloadService.class);
for(int i=0;i<filesArray.length;i++){
startService(intent);
}
The code basically starts an IntentService for every file in the array. Now I want to know how does the IntentService class queue up this threads or services and in particular I want to know how I can modify the IntentService class to stop 'end' the service and clear the queue from all the threads which are waiting to be processed. Really appreciate any help o this. It has been bothering me for quite some time now!!!!
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* #param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
/**
* Sets intent redelivery preferences. Usually called from the constructor
* with your preferred semantics.
*
* <p>If enabled is true,
* {#link #onStartCommand(Intent, int, int)} will return
* {#link Service#START_REDELIVER_INTENT}, so if this process dies before
* {#link #onHandleIntent(Intent)} returns, the process will be restarted
* and the intent redelivered. If multiple Intents have been sent, only
* the most recent one is guaranteed to be redelivered.
*
* <p>If enabled is false (the default),
* {#link #onStartCommand(Intent, int, int)} will return
* {#link Service#START_NOT_STICKY}, and if the process dies, the Intent
* dies along with it.
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
#Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
#Override
public void onDestroy() {
mServiceLooper.quit();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
*
* #param intent The value passed to {#link
* android.content.Context#startService(Intent)}.
*/
protected abstract void onHandleIntent(Intent intent);
}
EDIT:
I'm trying to Download multiples files one by one using an IntentService. However, when the Internet Connection is down the IntentService gets stuck on the current thread that it is processing or it just continues it's lifecycle. I want to end the service's lifecycle when the Internet connection is down.
EDIT:
I have copied the code for the IntentService and created a class MyIntentService using the same code. I have made the following changes to the code:
public volatile Looper mServiceLooper;
public volatile ServiceHandler mServiceHandler;
public String mName;
public boolean mRedelivery;
final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
the vars above have been made public and the inside class has been changed to final class. Now in my DownloadService which extends the MyIntentService I have a code like the following:
if(!isOnline()){
mServiceHandler.removeMessages(0);
mServiceLooper.quit();
stopSelf();
}
I'm checking first if we have Internet connection, if not then I'm removing the messages from the service handler's queue (assuming i'm doing it correctly), I'm stoping the loop, and i'm stoping the service which i'm not sure which service it is stopping. HEELP!!
An intent service will hold a queue of intents that are automatically run on a separate thread. The service lives for as long as there are messages to be processed. The messages are guaranteed to be run sequentially.
You have no control over when the service finishes it's lifecycle but that shouldn't matter to you. It is all transparent from your point of view.
EDIT: you will need to handle the queue manually and expose a method to clear it when needed.
I believe the Handler.removeMessages method will do the trick.
Also take a look at this: Drop intents while IntentService is processing
EDIT:
I have never done this myself and can't be sure if it will work. What you want is to set the "what" of the message before it is send so you can remove it after. In the onStart method a Message is obtained and two parameters are set. Also try setting the 'what' parameter.
The reason removeMessages wasn't working for you is because the what field of the Message is never set, you need to set that and then clear accordingly.