Receiver, that was created from IntentService, doesn't work - android

I have Geofence IntentService. On GEOFENCE_ENTER I create broadcast receiver. But it doesn't get actions.
If I created it in MainActivity - all is good. But I don't need to.
I do not understand what happens when I create the receiver from the service.
public class GeofenceTransitionsIntentService extends IntentService {
...
#Override
protected void onHandleIntent(Intent intent) {
...
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER) {
//Create WiFi scan receiver
WiFiScanReceiver wifiScan = new WiFiScanReceiver();
registerReceiver(wifiScan, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
//Scan
WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
Boolean scanStarted = wm.startScan();
}
}

Calling registerReceiver() in onHandleIntent() will not work well. Your receiver will go away microseconds later, after onHandleIntent() returns and the service stops itself.
Either use a manifest-registered receiver, or use a regular Service instead of an IntentService, managing your own background thread and arranging to stopSelf() the service when you are done with it.

IntentService will be destroyed once onHandleIntent() finished.
You should use 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" />

Can LocalBroadcastManager detect WifiManager.NETWORK_STATE_CHANGED_ACTION changes?

I'd like to notify my Activity of any Wifi connection changes using the BroadcastReceiver. Since this broadcast is within the application I'm trying to use the more efficient LocalBroadcastManager object.
However no matter what I do, the BroadcastReceiver.onReceive() method will not fire. I may have wired it up incorrectly, or perhaps the WifiManager.NETWORK_STATE_CHANGED_ACTION action I'm listening for cannot be registered against a LocalBroadcastManager? Any help or clarification would be appreciated.
Here's a sample of my Activity class which contains all the logic.
public class MyActivity extends ActionBarActivity {
private BroadcastReceiver wifiReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION))
{
// Do something
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
IntentFilter wifiStatusIntentFilter = new IntentFilter();
wifiStatusIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
wifiStatusIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(wifiReceiver, wifiStatusIntentFilter);
}
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(wifiReceiver);
}
protected void onResume() {
super.onResume();
IntentFilter wifiStatusIntentFilter = new IntentFilter();
wifiStatusIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(wifiReceiver, wifiStatusIntentFilter);
}
}
When I switch the wifi on my mobile on and off, or enter and leave the wifi range, the onReceive() method is never fired.
You can't receive WifiManager.NETWORK_STATE_CHANGED_ACTION with LocalBroadcastManager. LocalBroadcastManager works only within your process.
Helper to register for and send broadcasts of Intents to local objects
within your process. This is has a number of advantages over sending
global broadcasts with sendBroadcast(Intent):
You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.
It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes
they can exploit.
It is more efficient than sending a global broadcast through the system.
You should use registerReceiver of Context
Since this broadcast is within the application I'm trying to use the more efficient LocalBroadcastManager object.
That only works for broadcasts that you send via LocalBroadcastManager. It does not work for system broadcasts, particularly those sent by other processes.
perhaps the WifiManager.NETWORK_STATE_CHANGED_ACTION action I'm listening for cannot be registered against a LocalBroadcastManager?
Correct.

How to make an IntentService wait until BroadcastReceiver has finished executing?

I've got an IntentService which should perform some tasks after WiFi has been turned on.
I'm using a BroadcastReceiver on WifiManager.WIFI_STATE_CHANGED_ACTION to listen for WiFi changes.
The problem:
When I turn on WiFi via wifiManager.setWifiEnabled(true) the BroadcastReceiver only receives the states WifiManager.WIFI_STATE_DISABLED and WifiManager.WIFI_STATE_ENABLING. Then the IntentService is destroyed before the actual WifiManager.WIFI_STATE_ENABLED state can be received.
If I put Thread.sleep(2000) at the end of onHandleIntent() it works, but there must be a better solution?
Questions:
Why is the state WifiManager.WIFI_STATE_DISABLED broadcasted at all when I'm calling wifiManager.setWifiEnabled(true)?
How can I make the onHandleIntent() method wait until the state WifiManager.WIFI_STATE_ENABLED has been retrieved?
Code:
public class BackupService extends IntentService {
private BroadcastReceiver mWifiStateChangedReceiver;
public BackupService() {
super("BackupService");
}
#Override
protected void onHandleIntent(Intent intent) {
final WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
mWifiStateChangedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int wifiState = intent.getIntExtra(
WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN);
if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
// PERFORM TASK...
}
}
};
registerReceiver(mWifiStateChangedReceiver, new IntentFilter(
WifiManager.WIFI_STATE_CHANGED_ACTION));
wifiManager.setWifiEnabled(true);
}
#Override
public void onDestroy() {
super.onDestroy();
if (mWifiStateChangedReceiver != null) {
unregisterReceiver(mWifiStateChangedReceiver);
}
}
}
How can I make the onHandleIntent() method wait until the state WifiManager.WIFI_STATE_ENABLED has been retrieved?
Ideally, you don't, as WiFi may not be available, and so you may never receive such a broadcast.
Instead:
Move your BroadcastReceiver to be one registered in the manifest, initially disabled
If the IntentService determines that it needs to wait for WiFi, have it enable the existing BroadcastReceiver via PackageManager and setComponentEnabledSetting(), then return out of onHandleIntent()
The BroadcastReceiver would use startService() to send a command to be processed by your IntentService once WiFi is ready, at which point it can then disable itself via PackageManager and setComponentEnabledSetting()

how to stop Intent services in android

i have created one intent service. Now I want to stop that service from activity how to stop that service? My code is:
MyActivity.java
#Override
public void onCreate(Bundle savedInstanceState) {
Intent intent = new Intent(this, myService.class);
intent.putExtra("myHand", new Messenger(this.myHand));
startService(intent);
}
myService.java
public class myService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
String signal = intent.getAction();
if (signal != null && signal.equals("stop")) {
stopSelf();
} else {
t.schedule(new TimerTask() {System.out.println("print")}, 0, 10000);
}
}
}
to stop service on click of button
Intent in = new Intent(this, myService.class);
in.setAction("stop");
stopService(in);
can anybody help me to stop service?
From the docs for IntentService
IntentService is a base class for 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.
In other words, you don't have to stop an IntentService - it will terminate itself when it has no more work to do.
EDIT:
Looking back at your code, it seems you don't wan't to stop the IntentService you want to stop the TimerTask???
t.schedule(new TimerTask() {System.out.println("print")}, 0, 10000);
I don't know what t is but I'm guessing it's a Timer. If that's the case it will be running with its own Thread and attempting to terminate the IntentService is pointless - kill the Timer instead.
Also, why are you using an IntentService to create any type of object which maintains its own thread of execution?
Now I want to stop that service from activity how to stop that
service?
IntentService stops itself, you shouldn't, you can't call stopSelf().
When all requests have been handled, the IntentService stops itself.
From what I know, IntentHandler creates a separate new thread, does its work, and kills itself.
So I don't think you need to explicitly stop it from an activity.

Broadcast Receiver in IntentService (Service has leaked IntentReceiver)

I try to implement an IntentService with a BroadcastReceiver that reacts on the SCAN_RESULTS_AVAILABLE_ACTION.
The IntentService is supposed to compare Lists whenever onReceive is called. I always get the
"Service has leaked IntentReceiver"
error even though I unregister the BroadcastReceiver in onDestroy().
Here is the code:
public class MyClass extends IntentService {
private HashMap<String, List<String>>;
private WifiManager mWifiManager;
private WifiReceiver mWifiReceiver;
public MyClass() {
super("MyClass");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
mWifiReceiver = new WifiReceiver();
registerReceiver(mWifiReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY,"ScanLock");
mWifiManager.setWifiEnabled(true);
return START_NOT_STICKY;
}
#Override
public void onDestroy(){
unregisterReceiver(mWifiReceiver);
mWifiManager.setWifiEnabled(false);
}
#Override
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
}
class WifiReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Here I do my stuff with the scan results
//should be called every 5 seconds
}
}
Where is the problem in the code?
Why do I keep getting this error?
I still have to learn a lot about Android, but I think the IntentService is the right way to go since I do not expect any result from this class. It should just stop when I send a call stopService(). This IntentService is called by another IntentService! Is that a problem?
Thanks for helping.
I try to implement an IntentService with a BroadcastReceiver that reacts on the SCAN_RESULTS_AVAILABLE_ACTION.
This is largely pointless. Your receiver will be registered for a few seconds at most, hopefully.
I still have to learn a lot about Android, but I think the IntentService is the right way to go since I do not expect any result from this class.
That makes no sense whatsoever. You use an IntentService when you have a short bit of work that needs to be performed in a background thread. For example, if you use AlarmManager to check for new email messages every 15 minutes, or you have an activity kick off a large file download, you would use IntentService.
It should just stop when I send a call stopService().
You never call stopService() on an IntentService. The IntentService stops itself once onHandleIntent() returns. This is why your BroadcastReceiver will be removed within seconds -- your onHandleIntent() should only be running for seconds.
This IntentService is called by another IntentService!
This is unlikely to be a good design.
Try registering BroadcastReceiver in OnCreate() instead of OnStartCommand(),
That should fix your problem.

Categories

Resources