I want to stop LocationListener, but using a Log, I´ve found out that my service is still running after removeUpdates() method (When the location changes, it´s inserted into my log). Do you know where the problem is? Thanks in advance.
public class MyService extends Service implements LocationListener {
private final static String TAG = "MyService";
LocationManager lm;
public MyService() {
}
....//Other methods here
public void onLocationChanged(Location loc) {
Log.d(TAG, loc.toString());
if(/*A condition, which has to stop the service when it´s time*/)
{
lm.removeUpdates(this);
lm = null;
}
}
public void subscribeToLocationUpdates() {
this.lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
this.lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
#Override
public void onDestroy() {
}
}
I call this service in another Activity, onCreate method:
ComponentName comp = new ComponentName(getPackageName(),
MyService.class.getName());
ComponentName service = startService(new Intent().setComponent(comp));
The Service object and its lifecycle is independent of the state of your location manager. or any other object for that matter.
A service represents a background part of your app. once you are done with it you can call finish() method to end it.
So in your case :
public void onLocationChanged(Location loc) {
Log.d(TAG, loc.toString());
if(/*A condition, which has to stop the service when it´s time*/)
{
lm.removeUpdates(this);
lm = null;
stopSelf(); // end this service
}
}
Please take a look at android's Service documentation to get a general overview of its nature : Android Service
Related
I can't understand why onLocationChanged in not called in an Activity, while it is called in a service. Suppose I have a service:
public class LocationService extends Service implements LocationListener{
#override
public void onCreate() {
mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, this);
}
#Override
public void onLocationChanged(Location location) { //it is called
//do something with location
}
}
And I have an Activity:
public class ViewActivity extends AppCompatActivity implements OnMapReadyCallback, LocationListener{
#Override
public void onLocationChanged(Location location) { //it is not called
//do something with location
}
}
Is that because I haven't requested location updates in this activity? Why should I request it, if it was already done in the service.
Also, how should I spread my location through application correctly?
If it is done in your service, that means you need to start that service from the activity. If you have an activity like the one you are using with no request to location updates it onLocationChanged will not work.
This is the part where it actually calls the location updates
requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, this);
I see that you are trying to use the service in the background and received updates in the activity. Your possible solution is to send broadcast from the service inside onLocationChanged method, and receive it in the activity.
so from your service:
#Override
public void onLocationChanged(Location location) {
Intent intent = new Intent();
intent.setAction("com.myapp.LOCATION_CHANGED");
sendBroadcast(intent);
}
and your activity
#Override
public void onReceive(Context context, Intent intent) {
// do something
}
I am confused a little bit on the behavior of the service.I created a service class which is Emailing my location as soon as the latitude and longitude of My Device is changed.The Service is working perfect when the screen of my phone is on but as soon as the phone screen off the service is not updating me for new locations.I have read somewhere on the SO about wake lock.I don't know how can I implement wake lock on my service and even I don't know whether it will work or not.Please guide me how can I acquire wake lock on my service class
Code for my service class:
public class LocationUpdater extends Service {
private LocationManager lm;
private LocationListener locationListener;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(getApplicationContext(), "Location updater started",Toast.LENGTH_LONG).show();
locationListener = new MyLocationListener();
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0,0,
locationListener);
} else {
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,0, 0,
locationListener);
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,0, 0,
locationListener);
}
return START_STICKY;
}
#Override
public void onDestroy() {
lm.removeUpdates(locationListener);
super.onDestroy();
}
#Override
public void onCreate() {
Toast.maketext(getApplicationContext,"Updater Serive Created",Toast.LENGTH_LONG).show;
}
private class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
if (loc != null) {
String latitude=loc.getLatitude();
Striing longitude=loc.getLongitude();
emailMyLocation(latitude,longitude);
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
}
}
This is the service class which is updating the location of my device to my email.Please tell how can I make it work even if the screen is off.
You should check out answer for this question in the following thread: How can I keep my Android service running when the screen is turned off?. Probably, you need a partial WakeLock, which will keep CPU running even when the screen is turned off. You should also check documentation of PowerManager in Android API, which explains behavior of wake locks.
You can aquire the wake lock like this:
Make a Globals class and declare wakelock as static variable
public class Globals {
public static PowerManager.WakeLock wakelock;
}
Now in your service class Declare these:
PowerManager.WakeLock wakeLock ;
PowerManager pm;
Now you can have two functions for wakelocks:
public void acquirewakeLock() {
if(Globals.wakelock!=null){
Globals.wakelock.release();
Globals.wakelock=null;
}
pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"TrackerService");
wakeLock.acquire();
Globals.wakelock=this.wakeLock;
}
public void releaseWakelock() {
wakeLock.release();
}
Now in your onCreate method you can quire wakelock with this:
#Override
public void onCreate() {
acquirewakeLock()
}
This will take care of whether CPU is held by other activities and services or not.And you will be able to give cpu to your sevice class.
You can also use
wakelock.acquire(time in milliseconds)
if you know the time your service needs to process. :)
I implemented Android service for listening user location:
public class ListenLocationService extends Service {
IBinder mBinder = new LocalBinder();
public interface ILocationService {
Location userLocation = new Location("");
public void StartListenLocation();
public void StopListenLocation();
public Location getUserLocation();
}
LocationManager locationManager;
LocationListener locationListener;
public class LocalBinder extends Binder implements ILocationService{
public void StopListenLocation(){
//so many attempts to stop service and no one helped
locationManager.removeUpdates(locationListener);
locationListener = null;
stopSelf();
}
public void StartListenLocation()
{
locationManager = (LocationManager)ListenLocationService.this.getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListener() {
public void onStatusChanged(String provider, int status, Bundle extras) {
}
public void onProviderEnabled(String provider) {
}
public void onProviderDisabled(String provider) {
}
public void onLocationChanged(Location location) {
userLocation.set(location);
}
};
//if I have only one requestLocationUpdates situation is the same
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
400, 1, locationListener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
400, 1, locationListener);
}
public Location getUserLocation(){
return userLocation;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
I'm binding to this service in two activities. In first activity I'm just launching service:
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
mService = (ILocationService) service;
mService.StartListenLocation();
}
public void onServiceDisconnected(ComponentName arg0) {
Log.d("LOG","onServiceDisconnected");
}
};
public void onCreate(Bundle savedInstanceState) {
...
Intent intent = new Intent(this, ListenLocationService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
...
}
#Override
public void onStop(){
super.onStop();
unbindService(mConnection);
mService.StopListenLocation();
}
If I launch in my app only first activity and the close it then service stops - GPS mark disappear from device screen.
However if I enter the second activity (where I'm getting userLocation) and after this close both(using Android back button), then GPS mark still on my screen!
Code from second activity:
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
mService = (ILocationService) service;
userLocation = mService.getUserLocation();
}
public void onServiceDisconnected(ComponentName arg0) {
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
...
Intent intent = new Intent(this, ListenLocationService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
...
}
#Override
public void onStop(){
super.onStop();
unbindService(mConnection);
mService.StopListenLocation();
}
You can see that I wrote in both onStop() methods not only unbindService (initially I thought that it'll be enough) but I'm calling StopListenLocation function with this code:
locationManager.removeUpdates(locationListener);
locationListener = null;
stopSelf();
It stops service if only first activity was bound to it. However if both activities were bound, service doesn't stop after both onStop(). I used Log.d to get sure that all methods are called: onStop(), stopListenLocation(), onBind() etc. The only thing is that onServiceDisconnected() is not called ever.
I suppose situation is that my service starts another system service for listening location. I stop my service, but this system service that controls GPS continue to work despite of locationManager.removeUpdates(locationListener);. Maybe I'm mistaken in my suggestion.
How can I stop GPS where both activities are stopped?
BIND_AUTO_CREATE doesn't necessarily mean that the service will terminate itself when there are no connections, it just means that it's the first thing on the chopping block if the system needs resources. If the system is not resource starved, it will let your service continue to run, since, if your activity wants the service again, it is less expensive time-wise to bind to an existing instance than to create it from scratch.
In short, it will keep 'running', but don't worry about it - it's not consuming anything that is needed elsewhere.
EDIT: Also note that just because you have unbound from the service does not mean that it will interrupt any running processing tasks that the service is handling asynchronously. All that's happened is you've told the OS that you aren't interested in the results anymore. You must explicitly stop any running tasks before disconnecting from the service or that task will continue to consume CPU time
I have a service that gets the location and sends it to a server, also I have an activity that starts and stops the service with a button. When I start up the service all the buttons do not work and after a while the activity force closes giving the option to wait or close. what could be causing the problem?
I did something like that before ... I dont post the whole code, jsut the main thing. This wont run, i just want to give you the idea, of what to llok for and how to handle it.
The magic is done in sendUpdatesToUI... I saved myself all the unimportant methods that are overwritten when you implement LocationListener - you know best, which of them you need.
class:
public class ServiceLocator extends Service implements LocationListener
public static final String BROADCAST_ACTION = "my.app.isgreat";
private final Handler handler = new Handler();
private LocationManager locationManager;
Intent intent;
public void onCreate() {
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
intent = new Intent(BROADCAST_ACTION);
}
public void onStart(Intent intent, int startId) {
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, DEBUG_DELAY);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
DEBUG_DELAY, 3, this);
}
#Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(sendUpdatesToUI);
locationManager.removeUpdates(this);
locationManager = null;
}
//Here is the second thread, that won'z freeze your UI
//DisplayLogginInfo() sets all the values you wanna send
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
DisplayLoggingInfo();
handler.postDelayed(this, DEBUG_DELAY);
}
};
private void DisplayLoggingInfo() {
intent.putExtra("long", String.format("%.4f", lastLocation.getLongitude()));
sendBroadcast(intent);
}
It probably won't run that way, because I kicked out all the uninteresting stuff, but it should give you an idea, how to programm a locationthread, which won't freeze your UI.
Have fun
I am writing a location service App that log where the user has been every minute.
Should I create a service for the GPS process? OR just create the LocationManager at the Activity? Which one is better?
Moreover, I have tried to hide the application by pressing hardware home button and turn off GPS at Setting -> Location. I found that the App closed automatically within an hour.
Is it possible to keep the application always alive?
I highly recommend creating the gps at the very least as a thread in the activity, if you want to be slick set it up as a service and broadcast intents from inside an asynctask. Setting it up as a service makes it a bit modular if you want to use it for other applications or in other activities. Thats the way I implemented it.
Its also easier to control the lifetime of your gps readings if you run it from a service instead of your activity, so service doesnt get interrupted if you do switch activities etc.. example of asynctask portion below:
/** Begin async task section ----------------------------------------------------------------------------------------------------*/
private class PollTask extends AsyncTask<Void, Void, Void> { //AsyncTask that listens for locationupdates then broadcasts via "LOCATION_UPDATE"
// Classwide variables
private boolean trueVal = true;
Location locationVal;
//Setup locationListener
LocationListener locationListener = new LocationListener(){ //overridden abstract class LocationListener
#Override
public void onLocationChanged(Location location) {
handleLocationUpdate(location);
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status,
Bundle extras) {
}
};
/** Overriden methods */
#Override
protected Void doInBackground(Void... params) {
//This is where the magic happens, load your stuff into here
while(!isCancelled()){ // trueVal Thread will run until you tell it to stop by changing trueVal to 0 by calling method cancelVal(); Will also remove locationListeners from locationManager
Log.i("service","made it to do in background");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
#Override
protected void onCancelled(){
super.onCancelled();
stopSelf();
}
#Override
protected void onPreExecute(){ // Performed prior to execution, setup location manager
locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
if(gpsProvider==true){
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
if(networkProvider==true){
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
}
}
#Override
protected void onPostExecute(Void result) { //Performed after execution, stopSelf() kills the thread
stopSelf();
}
#Override
protected void onProgressUpdate(Void... v){ //called when publishProgress() is invoked within asynctask
//On main ui thread, perform desired updates, potentially broadcast the service use notificationmanager
/** NEED TO BROADCAST INTENT VIA sendBroadCast(intent); */
Intent intent = new Intent(LOCATION_UPDATE);
//Put extras here if desired
intent.putExtra(ACCURACY, locationVal.getAccuracy()); // float double double long int
intent.putExtra(LATITUDE, locationVal.getLatitude());
intent.putExtra(LONGITUDE, locationVal.getLongitude());
intent.putExtra(TIMESTAMP, locationVal.getTime());
intent.putExtra(ALTITUDE,locationVal.getAltitude());
intent.putExtra(NUM_SATELLITES,0);/////////////****TEMP
sendBroadcast(intent); //broadcasting update. need to create a broadcast receiver and subscribe to LOCATION_UPDATE
Log.i("service","made it through onprogress update");
}
/** Custom methods */
private void cancelVal(){ //Called from activity by stopService(intent) --(which calls in service)--> onDestroy() --(which calls in asynctask)--> cancelVal()
trueVal = false;
locationManager.removeUpdates(locationListener);
}
private void handleLocationUpdate(Location location){ // Called by locationListener override.
locationVal = location;
publishProgress();
}
}