android services and activity lifecycle? - android

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.

Related

Android Activity communication with IntentService

I need to have a two way communication between my activity and a running IntentService.
The scenario is like this: the app can schedule alarms which on run, start an IntentService which fetches some data from web and process it. There are three possible situations when IntentService finishes:
The app is in focus, which means that when the IntentService will finish, the app needs to refresh its views with the new data.
The app is closed and when opened after IntentService has finished the work, so the app will have access to processed data
The app is opened while the IntentService is running, in which case I need to have a way from the activity to ask the IntentService if its doing something in the background.
For 1. I have already implemented a BroadcastReceiver in my activity which gets registered with the LocalBroadcastManager. When IntentService finishes the work, sends a broadcast and the activity reacts. This works fine
For 2. There is nothing needed to be done
For 3. I don't know what to do. So far I've tried this:
In Activity:
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_SEND_TO_SERVICE));
In IntentService
private LocalBroadcastManager localBroadcastManager;
private BroadcastReceiver broadcastReceiverService = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BROADCAST_SEND_TO_SERVICE)) {
//does not reach this place
//Send back a broadcast to activity telling that it is working
}
}
};
#Override
protected void onHandleIntent(Intent intent) {
localBroadcastManager = LocalBroadcastManager.getInstance(context);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BROADCAST_SEND_TO_SERVICE);
localBroadcastManager.registerReceiver(broadcastReceiverService, intentFilter);
.... //do things
}
The problem with my implementation is that n the IntentService the BroadcastReceiver does not fire onReceive. Any suggestions or maybe a simpler way for the Activity to ask the IntentService what it is doing?
LE:
Trying to get atomicboolean.
In Service:
public static AtomicBoolean isRunning = new AtomicBoolean(false);
#Override
protected void onHandleIntent(Intent intent) {
isRunning.set(true);
// do work
// Thread.sleep(30000)
isRunning.set(false);
}
In Activity, restarting the app while service is running:
Log(MyIntentService.isRunning.get());
//this returns always false, even if the intent service is running
On AndroidManifest
<service
android:name=".services.MyIntentService"
android:exported="false" />

send Messages to service without binding it

i have created one service by extending Service in android and i am sending Message to service using Messenger and Handler.
But the issue (which is a common behavior though) is whenever i have to send message to Service i have to bind it and when i go out of activity i have to unbind it which eventually destroys the service itself.
i can keep running service in background by fringing startService method but is there any way to send Messages to service without using bind as i don't want to destroy the service when i go out of activity.
LocalBroadcastManager is a great way to send messages/data,
In your service class create a private broadcastreciever and string for the intent action name:
public static String MSERVICEBROADCASTRECEIVERACTION ="whatevs";
private BroadcastReceiver mServiceBroadcastReceiver= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("foo","onReceive called");
Log.d("foo","extra = " + intent.getStringExtra("foo")); // should print out " extra = bar"
}
};
And register it in your onCreate
#Override
public void onCreate() {
// your other code...
LocalBroadcastManager.getInstance(this).registerReceiver(mServiceBroadcastReceiver, new IntentFilter(ServiceClassName.MSERVICEBROADCASTRECEIVERACTION));
}
And De-register it in onDestroy()
#Override
public void onDestroy() {
// your other code...
LocalBroadcastManager.getInstance(this).unregisterReceiver(mServiceBroadcastReceiver);
}
As for sending messages to it, from an activity or fragment:
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
Intent intent = new Intent(ServiceClassName.MSERVICEBROADCASTRECEIVERACTION);
// add some data
intent.putExtra("foo","bar");
lbm.sendBroadcast(intent);
HTHs you send data without needing to bind!
Unbind Service will not destroy the service. it will disconnect the service connection between the activity and service
Make sure you return START_STICKY to keep your service running
#Override
public int onStartCommand(Intent intent, int flag, int startId)
{
return START_STICKY;
}
Also make sure your running the service as foreground
using notification to keep running the service after the application is removed from stack.
startForeground(1000,mBuilder.build()); // mBuilder - notification builder

Service not handling Intent when called from Receiver

Rarely I have an issue where a phone will get in a state (known as "funny state") where my Intent Services won't get a startService command from a Broadcast Receiver. (yes, the manifest has the receivers and services defined).
In this example I am listening for push notifications then calling a CheckinService.
Receiver:
public class PushReceiver extends BroadcastReceiver {
private static final String LOG_TAG = "push_receiver";
#Override
public void onReceive(Context context, Intent intent) {
logger.putExtra("debug", "Received Push");
Intent serviceIntent = new Intent(context, CheckinService.class);
context.startService(serviceIntent);
logger.putExtra("debug", "Sent to Service");
}
Service:
public class CheckinService extends IntentService {
private static final String LOG_TAG = "checkin_service";
public static final int SERVICE_ID = 3;
public CheckinService() {
super(LOG_TAG);
Log.i(LOG_TAG, "Service says: Checkin service started no constructor");
}
public CheckinService(String name) {
super(LOG_TAG);
Log.i(LOG_TAG, "Service says: Checkin service started with constructor");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.i(LOG_TAG, "Auto Checkin started");
.....tons of genius logic.....
}
}
So when the phone gets in the funny state the "received push" gets logged and the "sent to service" gets logged but the constructors and onHandleIntent methods of the service never get called.
I also have this happen not only on pushes but on receivers for inexactRepeatingAlarm and perhaps others but these two have been confirmed for sure.
Again this is very, very, rare and seems to happen after the phone has been left unused for a period of time; and perhaps goes into a power saving mode.
Also, terminating the application's process clears this up.
I realized what was happening here.
The IntentService is single threaded. So if something in my " .....tons of genius logic....." was blocking (like a http request with no timeout) the next intent that came into the service would not be processed.
Nice and humbling.

How do I cancel all pending intents that are qued for intent Service

I have an intentservice that gets qued by the user and by my app automatically. I need to be able to kill all pending intents that are qued when the user logs out of my application, but I cannot seem to get that to work. I have tried stopService() and stopself(), but the intents continue to fire off the intentservice after the user has logged out. I would try to get the id of the intent but that is difficult as everytime the intentservice starts, the variable holding the intent id's is empty. Here is my intentservice code:
public class MainUploadIntentService extends IntentService {
private final String TAG = "MAINUPLOADINTSER";
private GMLHandsetApplication app = null;
private SimpleDateFormat sdf = null;
public boolean recStops = true;
public MainUploadIntentService() {
super("Main Upload Intent Service");
GMLHandsetApplication.writeToLogs(TAG,
"GMLMainUploadIntentService Constructor");
}
#Override
protected void onHandleIntent(Intent intent) {
GMLHandsetApplication.writeToLogs(TAG, "onHandleIntent Started");
if (app == null) {
app = (GMLHandsetApplication) getApplication();
}
uploadData(app);
GMLHandsetApplication.writeToLogs(TAG, "onHandleIntent Finished");
}
#Override
public void onDestroy() {
GMLHandsetApplication.writeToLogs(TAG, "onDestroy Started");
app = null;
stopSelf();
GMLHandsetApplication.writeToLogs(TAG, "onDestroy completed");
}
public void uploadData(GMLHandsetApplication appl) {
//All of my code that needs to be ran
}
Unfortunately, I don't think it's possible to accomplish that with the standard IntentService methods since it doesn't offer a way to interrupt it while it's already going.
There are a few options I can think of that you can try to see if they fit your need.
Copy the IntentService code to make your own modifications to it that would allow you to remove pending messages. Looks like someone had some success with that here: Android: intentservice, how abort or skip a task in the handleintent queue
Instead of copying all the IntentService code, you might also be able to Bind to it like a normal Service (since IntentService extends Service) so you can write your own function to remove pending messages. This one is also mentioned in that link.
Rewrite the IntentService as a regular Service instead. With this option, you'd have more control over adding and removing messages.
I had what sounds like a similar situation where I was using an IntentService, and I eventually just converted it to a Service instead. That let me run the tasks concurrently and also cancel them when I needed to clear them.
Here
When should I free the native (Android NDK) handles? is the HangAroundIntentService class that has the method cancelQueue().
The class also has the method
public static Intent markedAsCancelIntent(Intent intent)
that converts an intent into a cancel intent, and
public static boolean isCancelIntent(Intent intent).
The class is based on the open-sourced Google's code.
Just a thought but inside of your onhandleintent can you have an argument that checks to see if app is running if not then don't run the code? example. In the start of your app you could have a static var
boolean appRunning;
Next in your onhandle of the intent, when you set the appRunning to false, after an onPause or onDestroy of activity, you could wrap the onhandleintent code in a boolean:
protected void onHandleIntent(final Intent intent) {
if(MainActivity.appRunning){
...
}
}
Just a thought

Handling connection change while loading data with IntentService

So I have a small little app which downloads a very small amount of data from the net. Everything else works just fine and downloads properly, but when connection changes (I lose wifi range) the download won't complete and the user doesn't get their data.
I have an idea how to handle this. I set up a BroadcastReceiver on my main Activity which communicates with my IntentService. When the IntentService completes the download, I then unregister the receiver. To top all this, I set up a Broadcastreceiver to listen connectivity changes and if connection is available, and if there is a connection, the main activity sends an Intent to start the download. See here:
Main Activity:
public class Sample extends Activity {
private BroadcastReceiver connectivityReceiver;
private ResponseReceiver receiver;
protected void onCreate(Bundle sis){
super.onCreate(sis);
IntentFilter intentFilter = new IntentFilter(
"android.net.conn.CONNECTIVITY_CHANGE");
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if (Network.isOnline()) {
fireUpDownloadingIntent();
}
}
}, intentFilter);
}
public class ResponseReceiver extends BroadcastReceiver {
public static final String ACTION_RESP = "com.irough.intent.action.URL_LOADED";
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getBooleanExtra(DLService.DOWNLOAD_COMPLETE, false) {
unRegisterReceiver(connectivityReceiver);
}
}
}
}
DLService.java:
public class DLService extends IntentService {
public static final String DOWNLOAD_COMPLETE = "dlc";
public DLService() {
super("DLService");
}
#Override
protected void onHandleIntent(Intent intent) {
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(ResponseReceiver.ACTION_RESP);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra(DOWNLOAD_COMPLETE, true);
sendBroadcast(broadcastIntent);
}
}
The code about should work just fine, but is there an easier or better way to do it? Doesn't have to be done on Service, Asynctask force closes on me when connection drops and that's why put the download action to a service.
If you lose the connection in your download, I imagine your download will throw some sort of exception. If I were, I'd simply notify the user (using the android notification api), and give them the option to try to redownload the data.
Preferably though, (and contrary to my previous post in a similar question), you could use my new favorite class in the android, the AsyncTaskLoader. It sounds like it exactly fits the bill for what you want to do here. Bascially, if there's an error downloading, just have your loader return null. Then in your onLoaderFinished hook in your activity, do what ever you need to do in regards to informing the user. Note that this class is only available to API levels 3 and above, but can still be accessed by lower API levels through the android compatibility package.

Categories

Resources