I have a service which is running in background process.This service is going to search for bluetooth devices after the application is killed by user.
<service android:name=".BLEBackgroundService"
android:enabled="true"
android:process=":externalBLEProcess"/>
in BLEBacgroundService class I have:
public class BLEBackgroundService extends Service{
.
.
.
public BLEDetector bleDetector;
public int onStartCommand(Intent intent, int flags, int startId) {
.
.
.
Log.i(tag,"onStartCommand");
startScan();
return START_STICKY;
}
void startScan() {
bleDetector.startScan();
Log.d(tag,"StartScan");
}
#Override
public void onDestroy() {
bleDetector.stopScan();
Log.w(tag,"Service OnDestroy");
super.onDestroy();
}
}
And in my BLEDetector class I have:
public class BLEDetector{
.
.
.
BluetoothAdapter mBAdapter;
public void stopScan(){
Log.i(tag,"StopScan");
mBAdapter.stopLeScan(stopCallback);
}
}
and in my activity here is how I start this service:
public class MyActivity extends AppCompatActivity{
Intent serviceIntent;
.
.
.
//This part is inside a Retrofit Callback onResponse
serviceIntent = new Intent(ItemListActivity.this,BLEBackgroundService.class);
serviceIntent.putExtra
(BasicUtils.getStringResource(getApplicationContext()
,R.string.beaconJsonIdentifier),new Gson().toJson(beaconModel));
serviceIntent.putExtra
(BasicUtils.getStringResource
(getApplicationContext(),R.string.currssiID), prgss);
if (BleUtil.isBluetoothEnabled(getApplicationContext()))
startService(serviceIntent);
}
public void disableService(){
stopService(serviceIntent);
}
And when I try to stop this service I just call disableService().
When I start service it calls onCreate successfully and service starts wroking on a seperate process which I can see logs from Logcat.But when I try to stop service it prints
Finally after reading this part of document I realized that sometimes my services onStartCommand function is called twice (which I have no idea why) and since I created bleDetector every time onStartCommand function was being called, I lost reference to it.
So all I had to do was to check to see if bleDetector was null or not.
How ever I have no idea why onStartCommand is being called multiple times.I call startService just once in my activity when I get a successful response from server using retrofit.
EDIT:
Sometimes in my activity, onResume is called multiple times and that's the reason why my startService is called multiple times.
Related
In my Android project, I have a normal Service:
public class MyService extends Service{
#Override
public int onStartCommand(...){...}
...
#Override
public void onDestroy() {
super.onDestroy();
Log.d("MyApp","MyService onDestroy() is called!");
}
}
In my BroadcastReceiver class, I stop MyService & do another task :
public static class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.stopService(new Intent(context, MyService.class));
doAnotherTask();
}
}
According to my log, onDestroy() of MyService is executed after doAnotherTask() is done.
How can I guarantee that onDestory() of MyService is executed before doAnotherTask() get called?
P.S.: I thought I could do something like:
boolean isStopped = context.stopService(new Intent(context, MyService.class));
if(isStopped){
doAnotherTask();
}
But it could be possible that there is no service has been started, which means stopService(...) does nothing. So, I can't rely on my above code.
call startActivityForResult() .... and after you got the onActivityResult,.... call your method doAnotherTask()
i think that will do the job
How about sending a special intent to your broadcast receiver from the onDestroy() function? When your receiver gets it, then call doAnotherTask(). (I am assuming that you can't simply call doAnotherTask() from onDestroy() directly.)
send a broadcast in the service's onDestroy function and in it's observer do your after things
The call to stopService() is asynchronous. You are basically telling Android that you want it to stop the Service. You have no control over when this actually occurs.
If you need to trigger something AFTER the Service is destroyed, then you send a broadcast Intent in MyService.onDestroy() and use that to trigger whatever you want to happen when the Service is destroyed.
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
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.
I'm currently writing unit tests for an android application and stumbled into the following issue:
I use the ServiceTestCase to test an IntentService like this:
#Override
public void setUp() throws Exception {
super.setUp();
}
public void testService()
{
Intent intent = new Intent(getSystemContext(), MyIntentService.class);
super.startService(intent);
assertNotNull(getService());
}
However I noticed that my IntentService is created (means that onCreate is called) but I never receive a call into onHandleIntent(Intent intent)
Has anyone already tested an IntentService with the ServiceTestCase class?
Thanks!
This is a bit late, but I just struggled with this. You could solve this by creating a class that simply overrides the onStart of you service so it calls onHandleIntent directly. So for instance, if you have a LocationUpdaterService, you could create a fake class that overrides the onStart function like this:
public class LocationUpdaterServiceFake extends LocationUpdaterService {
#Override
public void onStart(Intent intent, int startId) {
onHandleIntent(intent);
stopSelf(startId);
}
LocationUpdaterService is a subclass of IntentService, so when you write your tests, just use the LocationUpdaterServiceFake class like this
public class LocationUpdateServiceTest extends ServiceTestCase<LocationUpdaterServiceFake> {
public LocationUpdateServiceTest()
{
super(LocationUpdaterServiceFake.class);
}
public void testNewAreaNullLocation()
{
Intent intent = new Intent();
intent.setAction(LocationUpdaterService.ACTION_NEW_AREA);
startService(intent);
}
}
Now whenever you call startService, it will bypass the threading code in IntentService and just call your onHandleIntent function
I just got started into testing my own IntentService and it's proving to be a bit of a headache.
Still trying to work things out but for the scenario where it seems that you do not receive a call to your method onHandleIntent(), (I'm not very good with the technicalities behind junit so forgive my use of terminology) it should be because the test framework, based on your code, actually tears down or end the test method once your call to startService returns. There is insufficient time for onHandleIntent to be triggered.
I verified the above theory by adding an infinite loop within my test case - only then can I see my log statements in onHandleIntent logged.
You just have to add a:
Thread.sleep(XXXXXXX);
Choose the XXXX after the startService, then it will let the thread go into the onHandleIntent method.
In Android Studio 1.1, when running tests using the Run/Debug Configuration | Android Tests facility on any unit under test code (UUT) that extends IntentService, the ServiceTestCase.java (JUnit?) code does not call onHandleIntent(Intent intent) method in the UUT. ServiceTestCase only calls onCreate so the problem is in the test code.
protected void startService(Intent intent) {
if (!mServiceAttached) {
setupService();
}
assertNotNull(mService);
if (!mServiceCreated) {
mService.onCreate();
mServiceCreated = true;
}
mService.onStartCommand(intent, 0, mServiceId);
mServiceStarted = true;
}
In my file smSimulatorTest.java:
public class smSimulatorTest extends ServiceTestCase<smSimulator>
At this point, I'm looking for other solutions in the testing framework that test UUTs through Intents since this is how IntentService is instantiated.
http://developer.android.com/reference/android/app/IntentService.html - To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.
I, like others, put my code in the onHandleintent() as directed by the above documentation, however, ServiceTestCase only tests onStart and onStartCommand has shown above.
This is my approach for now:
The start Intent that invokes the service specifies the Service method to test
public void test_can_do_the_work() {
Intent startIntent = new Intent();
startIntent.putExtra("IN_TEST_MODE", "TEST_SPECIFIC_METHOD");
startIntent.setClass(getContext(), MyServiceToTest.class);
startService(startIntent);
assertNotNull(getService()); // Your assertion Service specific assertion
}
In the service onStart, we check for the specific Extra passed and call the method to test. This won't execute when Handle intent fired.
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
String in_test_mode = intent.getStringExtra("TEST_SPECIFIC_METHOD");
if(in_test_mode != null){
doServiceWork();
}
}
I am getting confused with all the different terminology when using Android: Activity, Service...
Right now I create a service:
startService(new Intent(this, RingerServer.class));
And this service starts a thread:
public class RingerServer extends Service {
public void onCreate() {
super.onCreate();
new Thread(new Ringer()).start();
}
public class Ringer implements Runnable { ... }
public void refuseConnection() { ... }
}
In this service, the RingerServer, I also have methods that I want to use. I would like to keep a reference to the RingerServer. I would basically like the Activity that created the service to be able to call refuseConnection(), but not make that method static.
startService returns a ComponentName, so I've been trying to cast it back to RingerServer but that doesn't seem to work. I see that it has getClass() and I've checked and getClassName() gives me the correct class. I haven't been able to use getClass() properly though.
Is there any way I can please keep a reference to the newly created RingerServer class? I am sure this is trivial, but I am stuck right now.
Thank you very much,
James
You have two options
1.Override onStartCommand of the service and start the server with intent using an action. that intent will be received in service, based on the intent action you can call refuseConnection()
//In Activity
...
//Start the service
Intent intent=new Intent("com.xx.xx.REFUSE_CONNECTION");
startService(this,intent);
...
//In Service
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
if(intent.getAction().equals("com.xx.xx.REFUSE_CONNECTION")){
//Refuse the connection
refuseConnection();
}else {
//Do something else
}
}
//In Manifest
<service android:name="RingerService">
<intent-filter>
<action android:name="com.xx.xx.REFUSE_CONNECTION"></action>
</intent-filter>
</service>
Implement AIDL interface and override onBind() of service , and use this interface to call refuseConnection(). Refer to this link http://developer.android.com/guide/developing/tools/aidl.html regarding AIDL.
You can use a ServiceConnection to get access to your service class. See sample code here:
Android service running after pressing Home key
That said, managing things via the service's onStart handler is much simpler.