dynamic broadcast receiver in a service not receiving intent - android

I have a dynamic broadcast receiver registered in a service and my service is doing some heavy sdcard read/write operation in a while(somecondition) loop.
When a broadcast is sent from my another Application (which is in other process) is not received by my broadcast receiver.
This same broadcast is received when it is not executing while loop.
I also tried to put end of loop with Thread.Sleep(100) just to give some time for broadcast receiver to get executed but it is not working.
Any help regarding this will help me a lot.
-Thanks & regards,
Manju
Code below for registering BxRx:
this.registerReceiver(myReceiver, new IntentFilter(ACTIVITY_NAME));
code below for sending broadcast:
Intent intnt = new Intent(ACTIVITY_NAME);
intnt.putExtra("STOP_ALL_TESTING", true);
Log.d(TAG,"Sending BX STOP_ALL_TESTING");
myActivity.this.sendBroadcast(intnt);
code below for while loop:
while(somecondition){
:
:
:
Thred.sleep(100);
}
public void onReceive(Context context, Intent intent) {
Log.d(TAG,"Received intent: "+intent.getAction());
boolean flag = intent.getBooleanExtra("STOP_ALL_TESTING", false);
Log.d(TAG,"Flag set to: "+flag);
if((boolean)intent.getBooleanExtra("STOP_ALL_TESTING",false)){
Log.d(TAG,"Broadcast received to STOP_ALL_TESTING");
Log.d(TAG,"Bx Rx, setting flag to stop testing as requested by user");
synchronized(this){
bStopTesting=true;
}
}
}

Please paste your complete code.
It looks like your problem is that you have an endless loop in service's onStartCommand method. Both onStartCommand and onReceive are executed on the same thread and only one after another. Applications main thread is a Looper thread, which handles events in a sequential manner. Basically, if you have an endless operation in the service, you will block the whole main thread, which includes all the GUI, services and Broadcast receivers. Calling Thread.sleep() won't help, because the method does not return. To avoid this, you can use IntentService http://developer.android.com/reference/android/app/IntentService.htmlclass, which will handle intents on another thread.
public class HeavyService extends IntentService {
public HeavyService() {
super("HeavyService");
}
#Override
public void onCreate() {
super.onCreate();
//do your initialization
}
#Override
protected void onHandleIntent(Intent intent) {
//this will be executed on a separate thread. Put your heavy load here. This is
//similar to onStartCommand of a normal service
}
}

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" />

how to stop Handler working in android?

My APP has to start some time consuming job when receiving ACTION_SCREEN_OFF, and interrupt the job when receiving ACTION_SCREEN_ON if job is still going on.
public class TimeConsumingWorkIntentService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
TimeConsumingWork();
}
}
public class ScreenStatusReceiver extends BroadcastReceiver {
Intent intent = new Intent(mContext, TimeConsumingWorkIntentService.class);
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
mContext.startService(intent );
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
mContext.stopService(intent );
}
}
}
By print log of time, I find time consuming work is still going on stop the TimeConsumingWorkIntentService (when receiving ACTION_SCREEN_ON).
why ?
Use
// Cancel the runnable
myHandler.removeCallbacks(yourRunnable);
Ok , then you can do something like this
Runnable r = new Runnable{
public void run(){
if(booleanCancelMember != false){
// within this you make the call to handler and work
// Since you block the call the handler wont get repeated
}
}
}
You can't do this like that. When you start your IntentService, it will call onHandleIntent() on a separate worker thread. That mehod then calls TimeConsumingWork(). Stopping the service will not interrupt the execution of the worker thread. It just tells the worker thread that when it has finished processing the current Intent, it should stop.
What you will need to do is to have your TimeConsumingWork() method periodically look to see if it should stop. You can do this by setting a static boolean variable and have TimeConsumingWork() periodically check this variable and quit if it is set.
You don't need to call stopService() on an IntentService as it will stop itself when it has nothing to do.

How to force an IntentService to stop immediately with a cancel button from an Activity?

I have an IntentService that is started from an Activity and I would like to be able to stop the service immediately from the activity with a "cancel" button in the activity. As soon as that "cancel" button is pressed, I want the service to stop executing lines of code.
I've found a number of questions similar to this (i.e. here, here, here, here), but no good answers. Activity.stopService() and Service.stopSelf() execute the Service.onDestroy() method immediately but then let the code in onHandleIntent() finish all the way through before destroying the service.
Since there is apparently no guaranteed way to terminate the service's thread immediately, the only recommended solution I can find (here) is to have a boolean member variable in the service that can be switched in the onDestroy() method, and then have just about every line of the code in onHandleIntent() wrapped in its own "if" clause looking at that variable. That's an awful way to write code.
Does anybody know of a better way to do this in an IntentService?
Here is the trick, make use of a volatile static variable and check continue condition in some of lines in your service that service continue should be checked:
class MyService extends IntentService {
public static volatile boolean shouldContinue = true;
public MyService() {
super("My Service");
}
#Override
protected void onHandleIntent(Intent intent) {
doStuff();
}
private void doStuff() {
// do something
// check the condition
if (shouldContinue == false) {
stopSelf();
return;
}
// continue doing something
// check the condition
if (shouldContinue == false) {
stopSelf();
return;
}
// put those checks wherever you need
}
}
and in your activity do this to stop your service,
MyService.shouldContinue = false;
Stopping a thread or a process immediately is often a dirty thing. However, it should be fine if your service is stateless.
Declare the service as a separate process in the manifest:
<service
android:process=":service"
...
And when you want to stop its execution, just kill that process:
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();
Iterator<RunningAppProcessInfo> iter = runningAppProcesses.iterator();
while(iter.hasNext()){
RunningAppProcessInfo next = iter.next();
String pricessName = getPackageName() + ":service";
if(next.processName.equals(pricessName)){
Process.killProcess(next.pid);
break;
}
}
I've used a BroadcastReceiver inside the service that simply puts a stop boolean to true. Example:
private boolean stop=false;
public class StopReceiver extends BroadcastReceiver {
public static final String ACTION_STOP = "stop";
#Override
public void onReceive(Context context, Intent intent) {
stop = true;
}
}
#Override
protected void onHandleIntent(Intent intent) {
IntentFilter filter = new IntentFilter(StopReceiver.ACTION_STOP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
StopReceiver receiver = new StopReceiver();
registerReceiver(receiver, filter);
// Do stuff ....
//In the work you are doing
if(stop==true){
unregisterReceiver(receiver);
stopSelf();
}
}
Then, from the activity call:
//STOP SERVICE
Intent sIntent = new Intent();
sIntent.setAction(StopReceiver.ACTION_STOP);
sendBroadcast(sIntent);
To stop the service.
PD: I use a boolean because In my case I stop the service while in a loop but you can probably call unregisterReceiver and stopSelf in onReceive.
PD2: Don't forget to call unregisterReceiver if the service finishes it's work normally or you'll get a leaked IntentReceiver error.
#Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
if (action.equals(Action_CANCEL)) {
stopSelf();
} else if (action.equals(Action_START)) {
//handle
}
}
Hope it works.
In case of IntentService it does not stop or takes any other request through some intent action until its onHandleIntent method completes the previous request.
If we try to start IntentService again with some other action, onHandleIntent will be called only when previous intent / task is finished.
Also stopService(intent); or stopSelf(); does not work until the onHandleIntent() method finishes its task.
So I think here better solution is to use normal Service here.
I hope it will help!
If using an IntentService, then I think you are stuck doing something like you describe, where the onHandleIntent() code has to poll for its "stop" signal.
If your background task is potentially long-running, and if you need to be able to stop it, I think you are better off using a plain Service instead. At a high level, write your Service to:
Expose a "start" Intent to start an AsyncTask to perform your background work, saving off a reference to that newly-created AsyncTask.
Expose a "cancel" Intent to invoke AsyncTask.cancel(true), or have onDestroy() invoke AsyncTask.cancel(true).
The Activity can then either send the "cancel" Intent or just call stopService().
In exchange for the ability to cancel the background work, the Service takes on the following responsibilities:
The AsyncTask doInBackground() will have to gracefully handle InterruptedException and/or periodically check for Thread.interrupted(), and return "early".
The Service will have to ensure that stopSelf() is called (maybe in AsyncTask onPostExecute/onCancelled).
As #budius already mentioned in his comment, you should set a boolean on the Service when you click that button:
// your Activity.java
public boolean onClick() {
//...
mService.performTasks = false;
mService.stopSelf();
}
And in your Intent handling, before you do the important task of committing/sending the intent information, just use that boolean:
// your Service.java
public boolean performTasks = true;
protected void onHandleIntent(Intent intent) {
Bundle intentInfo = intent.getBundle();
if (this.performTasks) {
// Then handle the intent...
}
}
Otherwise, the Service will do it's task of processing that Intent. That's how it was meant to be used,
because I can't quite see how you could solve it otherwise if you look at the core code.
Here is some sample code to start/stop Service
To start,
Intent GPSService = new Intent(context, TrackGPS.class);
context.startService(GPSService);
To stop,
context.stopService(GPSService);
context.stopService(GPSService);

How to wait for onReceive to finish while in same thread?

I have a BroadcastReceiver registered in the UI thread that grabs some information from the Bundle in its onReceive method. I need these values before I proceed in my main thread.
Is there any way to wait for the onReceive to finish before trying to use those values? I am running into timing issues where onReceive sets the values AFTER I try to use them. Having the thread sleep doesn't work, since they're on the same thread.
Would it make sense to register the receiver in an AsyncTask, and call wait() on the main thread, then have onReceive notify() once it completes?
String a = "hi";
IntentFilter filter = new IntentFilter();
filter.addAction(MY_CUSTOM_INTENT);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Set the variable values here
a = "bye";
}
};
getApplicationContext().registerReceiver(receiver, filter);
// Get the values, I am getting a = "hi" here because the onReceive code has
// not been reached yet
// How can I guarantee that a = "bye" from this method?
getA();
where method is something like
String getA() {
return a;
}
You seem to be over-complicating things. It's hard to know what you're really after based on the example code, but the code that comes after registerReceiver() should just do whatever else it needs to do and then return, without waiting for or hoping for the Broadcast to have been received. onReceive() should include whatever code you want to have executed at that point (which may well just be a method call, e.g. updateA("bye").
Well, if your going to block the main thread either way, might as well do it elegantly.. Register the receiver with the AsyncTask, and use a Dialog to let the user know what you are doing or that you are loading something.

The order when BroadcastReceiver starts a Service

I find that when a BroadcastReceiver starts a Service in onReceive() method, the return of onReceive() will happen before the onCreate() of the Service being invoked. Why does this happen in this order?
The example code is below: BroradcastReceiver's onReceive() method:
public void onReceive(Context context, Intent intent) {
Log.i("=====Receiver=======","===== onReceive starts===="); // (1)
intent.setClass(context, AService.class);
context.startService(intent);
Log.i("=====Receiver=======","===== onReceive ends===="); // (2)
}
Service's onCreate() method:
public void onCreate(){
Log.i("=======Service========", "========OnCreate()=== "); //(3)
// some logic here
}
The log order is (1)(2)(3),not (1)(3)(2).
Could anybody help explain it?
The service has its own thread, so I would guess it doesn't get to run until the thread executing onReceive yields. It could also be that startService posts an intent, but again it doesn't get handled until onReceive returns. I don't know the actual implementation, but I do know that startService is an asynchronous call, so you shouldn't be depending on the order of execution rrlated to onReceive.

Categories

Resources