Android Service's method onDestroy called before Bluetooth scanning ends - android

I have a problem that I start a service with an Intent, in onCreate() method register BroadcastReceiver and then in onDestroy() unregister the BroadcastReceiver. In Method onHandleIntent() I start discovery for bluetooth devices. THe problem is, that I my BroadcastReceiver is destroyed before any device is found so I cant really do anything with the BluetoothDevice.ACTION_FOUND intent. I tried to move startDiscovery() to onCreate() but no results. My code looks like this:
public class BluetoothService extends IntentService{
private BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
private final String SMART_TOKEN_ADDRESS = "F0:E7:7E:5F:63:70";
private final BroadcastReceiver receiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Log.v("BLUETOOTH","found it!");
}
};
public BluetoothService() {
super("BluetoothService");
// TODO Auto-generated constructor stub
}
#Override
public void onCreate(){
super.onCreate();
Log.v("SERVICE", "Just got created");
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver, filter);
btAdapter.startDiscovery();
}
#Override
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
Log.v("BLUETOOTH", "Discovery just started");
//btAdapter.startDiscovery();
}
#Override
public void onDestroy() {
super.onDestroy();
Log.v("BLUETOOTH","Just got destroyed!");
unregisterReceiver(receiver);
}
}
Log looks like this:
1. Just got created
2. Discovery just started
3. Just got destroyed!
4. Received android.bluetooth.device.action.FOUND
Thanks for help!
T.

This is happening because after handling all the requests, the service is stoped. From documentation: "Stops the service after all start requests have been handled, so you never have to call stopSelf()."
So, you should use wait or other command to tell the worker thread to wait the execution, if you want to use service.
Please, refer to the documentation about services: http://developer.android.com/guide/components/services.html

Related

OnReceive() method auto triggered

I have created the one receiver inside an Activity for when internet is connected auto calling web service.
Code like
//Create receiver for while network will come auto call webservice
private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if (!noConnectivity) {
bar.setVisibility(View.VISIBLE);
callAuthorizeWebservice();
} else {
bar.setVisibility(View.INVISIBLE);
Toast.makeText(SplashScreenActivity.this, "Check Your Internet connection", Toast.LENGTH_LONG).show();
}
}
};
#Override
protected void onStop() {
super.onStop();
unregisterReceiver(mConnReceiver);
}
#Override
protected void onStart() {
super.onStart();
this.registerReceiver(this.mConnReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
When I open that Activity the onReceive() is method called everytime.
How to avoid calling it the first time (when opening that Activity)?
The broadcast is sent when you register for the first time(cf sticky broadcast), a solution is to use isInitialStickyBroadcast in the onReceive callback of your BroadcastReceiver to know if you are actually proceeding a sticky broadcast and act accordingly (BroadcastReceiver : isInitialStickyBroadcast)

Service Automatic Called on Destroying Activity

I am stuck with the problem of Activity + Service in that I have following number of Activities and Services.
Activities:
LoginActivity => OrderListActivity => AddOrderActivity => ConfirmOrderActivity
Services:
ReceivingOrderService - Receiving New Data From Server
SendingOrderService - Sending new Data to Server
Above both Service Calling from another Separate Service on duration of some interval.
CheckAutoSyncReceivingOrder - To call ReceivingOrderService (Interval 15Mins)
CheckAutoSyncSendingOrder - To call SendingOrderService (Interval 3Mins)
CheckAutoSyncReceivingOrder:
public class CheckAutoSyncReceivingOrder extends Service {
Timer timer;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
if(timer != null) {
timer.cancel();
Log.i(TAG, "RECEIVING OLD TIMER CANCELLED>>>");
}
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
if(InternetConnection.checkConnection(getApplicationContext())) {
if(getDatabasePath(DatabaseHelper.DATABASE_NAME).exists())
startService(new Intent(CheckAutoSyncReceivingOrder.this, ReceivingOrderService.class));
} else {
Log.d(TAG, "Connection not available");
}
}
}, 0, 60000); // 1000*60*15 = 9,00,000 = 15 minutes
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if(timer != null)
timer.cancel();
Log.d(TAG, "Stopping Receiving...");
}
}
CheckAutoSyncSendingOrder:
public class CheckAutoSyncSendingOrder extends Service {
Timer timer;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
if(timer != null) {
timer.cancel();
Log.i(TAG, "OLD TIMER CANCELLED>>>");
}
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
Log.i(TAG, ">>>>>>>> SENDING AUTO SYNC SERVICE >>>>>>>>");
if(InternetConnection.checkConnection(getApplicationContext())) {
if(getDatabasePath(DatabaseHelper.DATABASE_NAME).exists())
startService(new Intent(CheckAutoSyncSendingOrder.this, SendingOrderService.class));
} else {
Log.d(TAG, "connection not available");
}
}
}, 0, 120000); // 1000*120*15 = 1,800,000 = 15 minutes
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if(timer != null)
timer.cancel();
Log.d(TAG, "Stopping Sending...");
}
}
ConfirmOrderActivity#Final Task which i have called for Insert Data:
new AsyncTask<Void, Void, Integer>() {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
progressDialog = new ProgressDialog(
ConfirmOrderProductActivity.this);
progressDialog.setMessage("Inserting "
+ (isInquiry ? "Inquiry" : "Order") + "...");
progressDialog.setCancelable(false);
progressDialog
.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.show();
}
#Override
protected Integer doInBackground(Void... params) {
// TODO Auto-generated method stub
int account_id = context.getSharedPreferences(PREF_DATA,
MODE_APPEND).getInt(DATA_ACCOUNT_ID, 0);
/**
* Check Whether isInquiry or not...
*/
product_type = isWeight ? 1 : 0;
if (isInquiry) {
/*
* INSERTING DATA IN INQUIRY TABLE
*/
return m_inquiry_id;
} else {
/*
* INSERTING DATA IN ORDER TABLE
*/
return m_order_id;
}
}
#Override
protected void onPostExecute(Integer m_order_id) {
// TODO Auto-generated method stub
super.onPostExecute(m_order_id);
progressDialog.dismiss();
if (dbHelper.db.isOpen())
dbHelper.close();
String title = "Retry";
String message = "There is some problem, Go Back and Try Again";
AlertDialog.Builder alert = new AlertDialog.Builder(
ConfirmOrderProductActivity.this);
if (m_order_id != -1) {
title = isInquiry ? "New Inquiry" : "New Order";
message = isInquiry ? "Your Inquiry Send Successfully." : "Your Order Saved Successfully.";
alert.setIcon(R.drawable.success).setCancelable(false);
} else {
alert.setIcon(R.drawable.fail).setCancelable(false);
}
alert.setTitle(title).setMessage(message)
.setPositiveButton("OK", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
dialog.dismiss();
startActivity(new Intent(
ConfirmOrderProductActivity.this,
FragmentChangeActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
/* Opening Left to Right Animation */
overridePendingTransition(R.anim.right_out,
R.anim.right_in);
}
});
AlertDialog alertDialog = alert.create();
alertDialog.show();
}
}.execute();
Everything is working fine as per flow of inserting records in database.
After Adding Inquiry:
Destroying Activity and Getting following Logcat:
Main Problem:
When I placed order successfully from ConfirmOrderActivity, It is displaying AlertDialog of Success Message which is cancellable false. When I Stop application from this Activity, Its calling both CheckAutoSyncReceivingOrder and CheckAutoSyncSendingOrder automatically.
Edited:
I am calling both Service from LoginActivity only, after that it
will called automatically after given intervals But Problem occurs
when I destroy ConfirmOrderActivity when dialog is shown.
I didn't know why it happens that Why its running automatically when I stop Activity Directly.
I have tried onStartCommand() with START_NON_STICKY in Service but not working. (as START_STICKY is default.)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
Is there any solution?
You need to either run your service in the foreground so when the activity is destroyed so will the service or use a bound service and manage the binding with the activity lifecycle, so it is not continually restarted when the activity is destroyed.
From this android docs tutorial Bound Services
You need to do this for each service.
public class CheckAutoSyncReceivingOrder extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
CheckAutoSyncReceivingOrder getService() {
return CheckAutoSyncReceivingOrder.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
From your activity that creates and calls the service, that when it is destroyed you want your service destroyed.
public class BindingActivity extends Activity {
CheckAutoSyncReceivingOr mService;
boolean mBound = false;
#Override
protected void onStart() {
super.onStart();
// Bind to CheckAutoSyncReceivingOr
Intent intent = new Intent(this, CheckAutoSyncReceivingOr.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to CheckAutoSyncReceivingOr, cast the IBinder and get CheckAutoSyncReceivingOr instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
And manage the service lifecycle. Restart the same service with your timer, do not create a new service.
public class ExampleService extends Service {
int mStartMode; // indicates how to behave if the service is killed
IBinder mBinder; // interface for clients that bind
boolean mAllowRebind; // indicates whether onRebind should be used
#Override
public void onCreate() {
// The service is being created
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// The service is starting, due to a call to startService()
return mStartMode;
}
#Override
public IBinder onBind(Intent intent) {
// A client is binding to the service with bindService()
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
// All clients have unbound with unbindService()
return mAllowRebind;
}
#Override
public void onRebind(Intent intent) {
// A client is binding to the service with bindService(),
// after onUnbind() has already been called
}
#Override
public void onDestroy() {
// The service is no longer used and is being destroyed
}
}
Note START_NOT_STICKY will only prevent the service from restarting if the device is low on memory.
Be mindful that you where you are starting services, just start it once and allow the service to maintain it's own lifecycle until you destroy it with your activity.
This is in reply to your original unedited question, when the app was mysteriously crashing:
You need to destroy the dialog before the context window the dialog is attached to. That will cause a problem. So this is where program flow and the order of closing and cleaning up resources is important. They, frequently have to be destroyed in the reverse order they were created if they are dependent upon parent windows (which is often in the form of a particular activity).
It's difficult to trace your code, so this is a generic answer.
Make use of onPause and onDestroy in your activities.
In all your activities, manage any resources you have created within that activity and with a null check, close them down. Like you have in your service class. If you want to override the parent onDestroy, place your custom code before super.onDestroy.
protected void onDestroy() {
if(timer != null)
timer.cancel();
Log.d(TAG, "Stopping Sending...");
super.onDestroy();
}
(1)For Your Dialog:
The solution is to call dismiss() on the Dialog you created before exiting the Activity, e.g. in onDestroy(). All Windows & Dialog should be closed before leaving an Activity.
(2)For Your service autostart:
you have to look at the value the service returns from its onStartCommand method. The default value is START_STICKY which will restart the service after it is destroyed. Take a look at the onStartCommand documentation for more details:
If the process that runs your service gets killed, the Android system will restart it automatically it is default behavior.
This behavior is defined by the return value of onStartCommand() in your Service implementation. The constant START_NOT_STICKY tells Android not to restart the service if it s running while the process is "killed".
You need to Override method onStartCommand() in your service class and move all your code from onStart() method to onStartCommand() method.
According to the Android Documentation:
For started services, there are two additional major modes of
operation they can decide to run in, depending on the value they
return from onStartCommand(): START_STICKY is used for services that
are explicitly started and stopped as needed, while START_NOT_STICKY
or START_REDELIVER_INTENT are used for services that should only
remain running while processing any commands sent to them
onStart() method calls each time when service is restarted but onStartCommand() method will not called if you return START_NON_STICKY.
Don't use onStart() anymore, it's deprecated.
I hope it helps you.
Services got killed when application got killed (add logs in service onStartCommand() and onDestroy() function and try clearing app from recent list and you will see onDestroy() is called. Android will re-start service if you have returned START_STICKY intent in onStartCommand()).
There are two approaches to fix your problem.
Either make your two services as foreground service.
Instead of using CheckAutoSyncReceivingOrder and CheckAutoSyncSendingOrder to schedule start of another services, you should use AlarmManager to schedule your task.

leaked Intent Receiver missing a call to unregisterReceiver

please before you don't like my question , please read the details .. what i am trying to do is to use a broadcast receiver when screen-off , so i want my app to start if the screen goes off .. here is my broadcast receiver code :
public class BootReceiver extends BroadcastReceiver {
public boolean screenoff;
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenoff = true;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenoff = false;
}
Intent intent1 = new Intent(context, ShakeService.class);
intent1.putExtra("screen_state", screenoff);
context.startService(intent1);
}
and here is the service code :
public class ShakeService extends Service{
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stu
return null;
}
#Override
public void onCreate() {
super.onCreate();
// REGISTER RECEIVER THAT HANDLES SCREEN ON AND SCREEN OFF LOGIC
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new BootReceiver();
registerReceiver(mReceiver, filter);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try{
Intent intent1 = new Intent(getApplicationContext(), SplashScreen.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return START_STICKY;
}
}
and here is my splash screen activity that i call from the service :
public class SplashScreen extends Activity {
private static int SPLASH_TIME_OUT=3000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_splash_screen);
ImageView imageView = (ImageView) findViewById(R.id.imageView1);
new Handler().postDelayed(new Runnable(){
public void run(){
Intent i =new Intent(SplashScreen.this,HomeScreen.class);
startActivity(i);
finish();
}
},SPLASH_TIME_OUT);
}
#Override
protected void onResume() {
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
BroadcastReceiver mReceiver = new BootReceiver();
registerReceiver(mReceiver, filter);
super.onResume();
}
#Override
protected void onPause() {
// mSensorManager.unregisterListener(mShakeDetector);
BroadcastReceiver mReceiver = new BootReceiver();
unregisterReceiver(mReceiver);
super.onPause();
}
}
and as you can noticed i have unregistered my receiver but still i keep seeing this in the logcat :
leaked Intent Receiver are you missing a call to unregisterReceiver??
I agree with the method of registering the receiver in onResume() and unregistering it in onPause(). This helps when the app goes in and out of scope. I'm somewhat confused on what you're trying to do with your app, but initially I see that you create a new instance of the braodcast receiver in onPause() and unregister that. Try unregistering using the same instance . Also, if you want your service to remain running in the background, you may want to look into implementation of a partial wake lock, that keeps the CPU running for your app while the screen remains off. Could you provide one more details about the purpose of the app?

Calling an Activity from a Service

I have a service class for an alarm service containing the service methods. These methods are called when the alarm service is activated. What I want to do is to call an intent to another class in one of these methods that are called in the service class (when the alarm goes off). All it does is just flag up errors when calling the intent. This only happens in the methods that are called when the alarm service is activated (methods in service class). Is this because the class extends Service and not extends Activity? I'm not sure, any ides?
(Below is my service class, when the intent to another activity is called in the onStart method the app force closes.)
public class MyAlarmService extends Service {
#Override
public void onCreate() {
// TODO Auto-generated method stub
Toast.makeText(this, "MyAlarmService.onCreate()", Toast.LENGTH_LONG).show();
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Toast.makeText(this, "MyAlarmService.onBind()", Toast.LENGTH_LONG).show();
return null;
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Toast.makeText(this, "MyAlarmService.onDestroy()", Toast.LENGTH_LONG).show();
}
#Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
Toast.makeText(this, "MyAlarmService.onStart()", Toast.LENGTH_LONG).show();
//////////////////////////////////////////////////////////////////////////////////
Intent i = new Intent("com.exercise.AndroidAlarmService.HELLO");
startActivity(i);
The intent that is send to open another class, an activity.
**
/////////////////////////////////////////////////////////////////////////////////
}
#Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
Toast.makeText(this, "MyAlarmService.onUnbind()", Toast.LENGTH_LONG).show();
return super.onUnbind(intent);
}
}
One of these errors on the LogCat is:
06-24 01:11:36.857: E/AndroidRuntime(10805): java.lang.RuntimeException: Unable to start service com.exercise.AndroidAlarmService.MyAlarmService#412f23f8 with Intent { flg=0x4 cmp=com.exercise.AndroidAlarmService/.MyAlarmService (has extras) }: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
Have you tried what the error log suggests?
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
You can call an Activity using onStart() of your service.....
#Override
public void onStart(Intent intent, int startId) {
...
Log.i("Service", "onStart() is called");
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
callIntent.setClass(<Set your package name and class name here>);
startActivity(callIntent);
...
}
You can do it by enabling the flag as suggested by others. The reason why it is prevented by default is because services are prone to automatic restart by system, in the background. If you are starting an activity during onStart of a service, this activity starts irrespective of what the user may be doing. This will be bad user experience. Please bear this caveat in mind and have work around for this scenario.

Register Battery Changed broadcast in Android service

I'm starting a service from an Activity. The service registers for Battery Changed broadcast Receiver. I receive broadcasts as long as the screen is ON. Once the screen is turned OFF, I stop receiving broadcasts, however, the service doesn't die.
My activity code,
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = this.getApplicationContext();
Intent intent = new Intent(this,BatteryStatusService.class);
startService(intent);
}
and my service code,
public class BatteryStatusService extends Service{
private final static String TAG = BatteryStatusService.class.getSimpleName();
private BroadcastReceiver timeTickReceiver;//changeReceiver;
private boolean registered = false;
public class LocalBinder extends Binder {
BatteryStatusService getService() {
return BatteryStatusService.this;
}
}
private final IBinder mBinder = new LocalBinder();
#Override
public void onStart(Intent intent, int startId){
Log.i(TAG,"Starting service");
IntentFilter filter = new IntentFilter();
filter.addAction(Constants.ACTION_BATTERY_CHANGED);
timeTickReceiver = new TimeTickReceiver();
this.getApplicationContext().registerReceiver(timeTickReceiver, filter);
registered = true;
}
#Override
public void onDestroy(){
Log.d(TAG,"Stopping service");
if(registered){
this.getApplicationContext().unregisterReceiver(timeTickReceiver);
}
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mBinder;
}
public class TimeTickReceiver extends BroadcastReceiver {
private String action = null;
private final String TAG = TimeTickReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
action = intent.getAction();
if(action.equals(Constants.ACTION_BATTERY_CHANGED)){
Log.d(TAG,"I got action = "+action);
}
}
}
}
}
use AlarmManager and get last broadcasted level with
Intent BATTERYintent=this.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
However there are mobiles where it would work either. I have t-mobile MOVE which will not update battery value/broadcast no matter what in sleep mode... but most mobiles will do it as they should
by the way dont listen to dcanh121 there are cases when u need to get battery level even when phone is in sleepmode.
Once the screen is turned OFF, I stop receiving broadcasts, however, the service doesn't die.
When the screen is turned off, shortly thereafter the device goes into sleep mode. Your code does not execute again until something wakes up the device from sleep mode.
Also:
You do not need to use getApplicationContext() here
You do not need a Binder here, since you are not binding to the service, so just have onBind() return null
You need to have some code somewhere to stop this service, so it does not run forever
why don't you try by using onResume() and onPause()

Categories

Resources