I want to call LocationListener Service from BroadcastReceiver, So I can get current location of device and call my API on server after every 5 minutes in backend, even if application is not running.
So, I have created class with BroadcastReceiver, Which will call my LocationListener Service. In this service, I want to get location and save it in db.
The problem is, I am not able to call LocationListener Service from BroadcastReceiver. BroadcastReceiver running well.
Code,
Run BroadcastReceiver in AlarmManager.
public void LocationClicked(View view){
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval = 10000;
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
Toast.makeText(this, "Alarm Set", Toast.LENGTH_SHORT).show();
}
BroadcastReceiver class file,
public class LocationReceiver extends BroadcastReceiver {
private static int count = 0;
#Override
public void onReceive(Context context, Intent intent) {
count++;
Toast.makeText(context, "I'm running " + count, Toast.LENGTH_SHORT).show();
Intent myIntent = new Intent(context, LocationUpdateService.class);
context.startService(myIntent);
}
}
"I'm running " is coming.
LocationListerner Service file,
public class LocationUpdateService extends Service implements LocationListener {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onLocationChanged(Location location) {
double ss = location.getLatitude();
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
}
}
Here what do I need to change to make it work ?
And tell me If I am doing it in wrong way.
Related
I have a service that gives a notification if user has changed his location. I want this service to keep on running until user explicitly force stops my application in application manager. I have used following method:
Intent intent1 = new Intent(context, LocationService2.class);
PendingIntent contentIntent = PendingIntent.getService(context, 0, intent1, 0);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(),2*60000, contentIntent);
Service class:
public class LocationService2 extends Service implements GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("TAG", "STARTLS");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
return START_STICKY;
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Location services connected.");
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
// Use this location to give notification if required.
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Location services suspended. Please reconnect.");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
mGoogleApiClient.disconnect();
}
}
This method does not work on all phones.
Is AlarmManager the best way to do this. If yes, then how can I improve this code to work on all phones?
You should make your service a Foreground Service. You can find a tutorial here.
Manifest Entry
<receiver android:name="YourPackagename.RestartReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name="YourPackagename.AlarmReceiver" >
</receiver>
On phone reboot need to reinitialize alarm manager
RestartReceiver.java
public class RestartReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intentReciever = new Intent(context, AlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intentReciever, 0);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, (System.currentTimeMillis() + GlobalContext.PUSH_NOTIFICATION_INTERVAL),
GlobalContext.PUSH_NOTIFICATION_INTERVAL, alarmIntent);
}
}
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//you can put your logic over here
}
}
Put below code in your Splash Screen
private void initService() {
if(!app_preferences.getBoolean("isServiceRunning", false))
{
AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intentReciever = new Intent(LoadingScreen.this, AlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(LoadingScreen.this, 0, intentReciever, 0);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, (System.currentTimeMillis()+GlobalContext.PUSH_NOTIFICATION_INTERVAL),
GlobalContext.PUSH_NOTIFICATION_INTERVAL, alarmIntent);
app_preferences.edit().putBoolean("isServiceRunning", true).commit();
}
}
//Note: its not good way to check your Alerm service using shared preference is running or not.
The steps to make a never ending service are :
1.) Start service using alarmManager.
2.) Check in onResume if service is running & restart if not.
3.) Return START_STICKY from onStartCommand().
4.) In OnStartCommand() , create a thread and do the needful from that thread .All the logical stuff should be there in while(true).
This way your service will never be killed .
In given code i have put some good things like you can communicate with activity using binder service via listner. You can notify your activity that you lost internet connction by writing code in service...
Create service as sticky which will never end. if user will kill app it will again automatically restart.
When compare to alarm manager you may face duplication/multiple service get started. like we need to identify and prevent that if Alarm manager already i have created then don't start again as per my another answer written in same question.
Manifest.xml
<receiver android:name=".BootCompleteReceiver"><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED"/></intent-filter></receiver>
<service android:name=".MyService" android:enabled="true" android:exported="false"/>
MyService.java
public class MyService extends Service {
CommunicationListner listener;
public class LocalBinder extends Binder {
public MyService getService() {
// Return this instance of LocalService so clients can call public methods
return MyService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
unregisterReceiver(internetConnectionReceiver);
} catch (Exception e) {
}
registerReceiver(internetConnectionReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
//communication with activity
public void registerChatReceivedListener(CommunicationListner listener) {
this.listener = listener;
}
public void removeChatReceivedListener() {
chatListener = null;
}
private BroadcastReceiver internetConnectionReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
};
public MyService() {
}
}
To restart your service on restart phone
BootCompleteReceiver.Java
public class BootCompleteReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
context.startService(new Intent(context, MyService.class));
}
}
}
Put code in you splash screen to start myservice if its already started then also no need to worry.
startService(new Intent(getApplicationContext(), MyService.class));
Start the service anytime it got killed.
#Override
public void onDestroy() {
super.onDestroy();
mGoogleApiClient.disconnect();
startService(new Intent(this, LocationService2.class));
}
The solutions in android 5 and higher is using AlarmManger and Broadcast Receiver
I'm new to services and BroadcastReceiver so maybe this question is newbie, but I didn't found the solution for my question after a long search on the web.
I need to run a CountDownTimer inside service, so the time keep moving even the application was finished.
In my code I based on THIS EXAMPLE.
My code works fine, but after the application is finished the CountDownTimer stopped(The service doesn't destroyed, just the timer).
I tried to implement it in different ways, but nothing works for me.
This is the part of my code that relevant:
AlarmReciver:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent background = new Intent(context, BackgroundService.class);
Bundle bundle = intent.getExtras();
background.putExtra("time", bundle.getInt("time"));
context.startService(background);
}
}
BackgroundService :
public class BackgroundService extends Service {
private final static String TAG = "BroadcastService";
private CountDownTimer cdt = null;
private Bundle bundle;
private boolean isRunning;
private Context context;
private int timeInMili;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
this.context = this;
this.isRunning = false;
}
#Override
public void onDestroy() {
//cdt.cancel();
Log.i(TAG, "Timer cancelled");
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
bundle = intent.getExtras();
timeInMili = bundle.getInt("time");
if(!this.isRunning) {
this.isRunning = true;
}
cdt = new CountDownTimer(timeInMili, 1000) {
#Override
public void onTick(long millisUntilFinished) {
Log.i(TAG, "Countdown seconds remaining: " + millisUntilFinished / 1000);
}
#Override
public void onFinish() {
Log.i(TAG, "Timer finished");
stopSelf();
}
};
cdt.start();
return START_STICKY;
}
}
MainActivity (extends FragmentActivity):
public void StartBackgroundAlarm(int timeInMili)
{
Intent alarm = new Intent(this, AlarmReceiver.class);
alarm.putExtra("time", timeInMili);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarm, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), pendingIntent);
}
MANIFEST :
<service android:enabled="true" android:name= "com.MES.yo.servicemanager.BackgroundService" />
<receiver android:name="com.MES.yo.servicemanager.AlarmReceiver"></receiver>
I have a Bound service which collects locations for 3 minutes every 15 minutes. I start a CountDownTimer once the Service is connected in onServiceConnected of ServiceConnection.
I receive all the Timer callbacks (onFinish) (onTick) perfectly as far the Activity which bindService is visible.
When Device is locked I do not receive any updates from the timer.
MyLocationService
public class MyLocationService extends Service implements MyTimerListener{
private IBinder mBinder = new MyLocationBinder();
public void onCreate() {
locationManager = new MyLocationManager(this);
}
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class MyLocationBinder extends Binder
{
public MyLocationService getService()
{
return MyLocationService.this;
}
}
public void startFetchingLocations()
{
if(locationManager != null){
locationManager.startFetchingLocations();
if(publishPeriodCountDownTimer != null) {
publishPeriodCountDownTimer.cancel();
publishPeriodCountDownTimer = null;
}
publishPeriodCountDownTimer = new MyCountTimer(gpsPublishPeriod * 60 * 1000, 1000, MyLocationService.this);
publishPeriodCountDownTimer.start();
}
}
#Override
public void onTimeFinished() {
//Start fetching locations
locationManager.startFetchingLocations(); //Start 3 min CountdownTimer
}
#Override
public void onTick() {
}
public void onAllLocationsRecieved(ArrayList<Location> locations)
{
//Do stuff on Locations
locationManager.stopFetchingGPS(); //Stops 3 min countdownTimer
}
}
MyActivty
public class MyActivity
{
#Override
protected void onStart() {
super.onStart();
btnStop.setVisibility(View.VISIBLE);
MyNoificationManager.cancelAllNotifications();
if (!isLocationServiceBound) {
Intent locServiceIntent = new Intent(this, MyLocationService.class);
bindService(locServiceIntent, locationServiceConnection, Context.BIND_AUTO_CREATE);
}
}
private ServiceConnection locationServiceConnection = new ServiceConnection(){
#Override
public void onServiceDisconnected(ComponentName name) {
isLocationServiceBound = false;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyLocationBinder locationBinder = (MyLocationBinder) service;
locationService = locationBinder.getService();
isLocationServiceBound = true;
locationService.startFetchingLocations();
}
};
}
It works as expected when the Activity is visible. The timer doesn't provide any onTick() or onTimeFinished() callbacks when the device is locked.
What could be the problem here ?
The CountDownTimer will not work when the phone goes to sleep mode. This is by design and it's to save battery life.
Alternately you can use android.app.AlarmManager instead to achieve your goal. Following is the sample code how to do that. Set the alaram like below
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, MyLocationService.class);
intent.putExtra("need_to_fetch_loc", true);
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
alarmManager.set(AlarmManager.RTC_WAKEUP, gpsPublishPeriod * 60 * 1000, alarmIntent);
Add the following method to your MyLocationService class
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(locationManager!= null && intent.getBooleanExtra("need_to_fetch_loc", false))
{
locationManager.startFetchingLocations();
}
return super.onStartCommand(intent, flags, startId);
}
i want a background service class that which will get the user current location sends as a notification to the user if the user changes its location then the updated location will sends back to the user as a notification..even if the user close the application then also will receive the notification (the service will trace the location in background even application closed)
currently i am using this service for tracing the location which works if the application in foreground
can u pls. help me to get out of this i am struggling for 4 hours
in your activity unlike the one that you are using make your buttons start and stop the service and it will run in the background unless the user reopens the app and stops it
Intent i = new Intent(MainActivity.this,gpsservice.class);
startService(new Intent(i));
or to stop
Intent j = new Intent(MainActivity.this,gpsservice.class);
stopService(new Intent(j));
use this service
public class gpsservice extends Service{
private LocationManager locationManager;
MyLocationListener locationListenerp;
public gpsservice() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
locationManager = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);
locationListenerp = new MyLocationListener();
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 5000, 10, locationListenerp);
}
#Override
public void onDestroy() {
locationManager.removeUpdates(locationListenerp);
}
#Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "location Service Started", Toast.LENGTH_LONG).show();
}
public class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location location) {
Toast.makeText(getApplicationContext(), "I was here", Toast.LENGTH_LONG).show();
}
#Override
public void onProviderDisabled(String s) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
// TODO Auto-generated method stub
}
}
}
In a Splash Activity's onResume(), I start the service this way
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent i = new Intent(this, LocationService.class);
PendingIntent pi = PendingIntent.getService(this, 0, i,
PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pi);
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
ystemClock.elapsedRealtime() + 20000, 60000, pi);
and in onStop(), I stop the service this way
stopService(new Intent(this, LocationService.class));
and the Service Class is:
public class LocationService extends Service implements LocationListener {
private LocationManager mgr;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mgr = (LocationManager) getSystemService(LOCATION_SERVICE);
//get Location details
mgr.requestLocationUpdates(LocationManager.GPS_PROVIDER,
10 * 60 * 1000, 50, this);
return START_NOT_STICKY;
}
private void dumpLocation(Location l) {
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onDestroy() {
super.onDestroy();
mgr.removeUpdates(this);
}
}
Once I stop the service in Splash Activity's onStop(), onDestroy() of the LocationService is triggered(which means the service is stopped?), but still after a minute as specified in the AlarmManager the service runs.
Store the pending intent for the alarm in a variable. Call cancel on it when the service ends.