Background Service gets killed on clearing from recents in MIUI - android

Jugnoo Driver App has not been whitelisted in the Auto Start but yet it again starts the service after some time !
How jugnoo rider app runs even it is not Auto start too
I have done notification stuff , changed the manifest to stopWithTask="false" .

I have created a service for same issue,
please check it out with this.
It will help you
public class GpsServices extends Service implements LocationListener, GpsStatus.Listener {
Data data;
private LocationManager mLocationManager;
private SharedPreferences sharedPreferences;
private Data.onGpsServiceUpdate onGpsServiceUpdate;
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
public String gps_notification = "gps_channel";
#SuppressLint("MissingPermission")
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (data == null) {
data = new Data(onGpsServiceUpdate);
} else {
data.setOnGpsServiceUpdate(onGpsServiceUpdate);
}
gpsListener();
mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
if (mLocationManager.getAllProviders().indexOf(LocationManager.GPS_PROVIDER) >= 0) {
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 500, 0, this);
} else {
Log.w("SideMenuActivity", "No GPS location provider found. GPS data display will not be available.");
}
if (!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Toast.makeText(this, "Gps not enabled", Toast.LENGTH_SHORT).show();
}
}
public void onLocationChanged(Location location) {
Gson gson = new Gson();
String json = sharedPreferences.getString("data", "");
data = gson.fromJson(json, Data.class);
if (data == null) {
data = new Data(onGpsServiceUpdate);
} else {
data.setOnGpsServiceUpdate(onGpsServiceUpdate);
}
String speed = String.format(Locale.ENGLISH, "%.0f", location.getSpeed() * 3.6);
Toast.makeText(this, speed, Toast.LENGTH_SHORT).show();
Log.e("isRunningFalse", speed);
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;//needed for stop.
if (intent != null) {
msg.setData(intent.getExtras());
mServiceHandler.sendMessage(msg);
} else {
Toast.makeText(GpsServices.this, "The Intent to start is null?!", Toast.LENGTH_SHORT).show();
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
/* Remove the locationlistener updates when Services is stopped */
#Override
public void onDestroy() {
mLocationManager.removeUpdates(this);
mLocationManager.removeGpsStatusListener(this);
stopForeground(true);
}
#Override
public void onGpsStatusChanged(int event) {
switch (event) {
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
#SuppressLint("MissingPermission") GpsStatus gpsStatus = mLocationManager.getGpsStatus(null);
int satsInView = 0;
int satsUsed = 0;
Iterable<GpsSatellite> sats = gpsStatus.getSatellites();
for (GpsSatellite sat : sats) {
satsInView++;
if (sat.usedInFix()) {
satsUsed++;
}
}
if (satsUsed == 0) {
data.setRunning(false);
stopService(new Intent(getBaseContext(), GpsServices.class));
// firstfix = true;
}
break;
case GpsStatus.GPS_EVENT_STOPPED:
if (!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Toast.makeText(this, "Gps not enabled.", Toast.LENGTH_SHORT).show();
}
break;
case GpsStatus.GPS_EVENT_FIRST_FIX:
break;
}
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
//promote to foreground and create persistent notification.
//in Oreo we only have a few seconds to do this or the service is killed.
Notification notification = getNotification("App is running");
startForeground(msg.arg1, notification); //not sure what the ID needs to be.
// Normally we would do some work here, like download a file.
// For our example, we just sleep for 5 seconds then display toasts.
//setup how many messages
int times = 1, i;
Bundle extras = msg.getData();
if (extras != null) {
times = 1000*60*60*24; //default is one
}
//loop that many times, sleeping for 5 seconds.
for (i = 0; i < times; i++) {
synchronized (this) {
try {
wait(5000); //5 second sleep
} catch (InterruptedException e) {
}
}
String info = i + "GPS SPEED LOG";
Log.d("intentServer", info);
//make a toast
//unable to ensure the toasts will always show, so use a handler and post it for later.
// Toast.makeText(MyForeGroundService.this, info, Toast.LENGTH_SHORT).show();
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
// stopSelf(msg.arg1); //notification will go away as well.
}
}
// build a persistent notification and return it.
public Notification getNotification(String message) {
return new NotificationCompat.Builder(getApplicationContext(), gps_notification)
.setSmallIcon(android.R.drawable.ic_menu_mylocation)
.setOngoing(true) //persistent notification!
.setChannelId(gps_notification)
.setContentTitle("Gps Service") //Title message top row.
.setContentText(message) //message when looking at the notification, second row
.build(); //finally build and return a Notification.
}
}

Related

how to stop a service running multiple instance?

I am developing a android app, which will update device location after 4 seconds interval and depending on the response received from the server it will open specific activity.
Problem 1) In some case it will open up a activity like incoming phone call with sound. I am facing problem when I am removing the app from recent app. I noticed the poll function is running twice at the same time, and multiple media is playing at the same time.
Problem 2) I am using Service intead of IntentService(I am a beginner and not sure which will be better). The background service should run even the phone goes to sleep mode, just like WhatsApp or other messenger run.
As the file is big enough, I am attaching only important part
public class TaxiNorrService extends Service implements LocationListener {
...
...
final Handler poll_handler = new Handler();
private NotificationManager mNM;
private final Actions actions = new Actions();
public Ringtone r;
private String newtext;
private Runnable BreakRunnable;
private Runnable poll_runnable;
private Handler BreakHandler;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
poll_runnable = new Runnable() {
#Override
public void run() {
if(!App.isAutoBreak()){
if(BreakHandler !=null){
BreakHandler.removeCallbacks(BreakRunnable);
}
if(r != null) {
if (r.isPlaying()) {
r.stop();
}
}
}
if (actions.checkPermission(getApplicationContext())) {
checkGPS();
if(isNetworkAvailable()){
if(App.isPollOn()){
poll(latitude, longitude);
}
}else{
if(BreakHandler !=null){
BreakHandler.removeCallbacks(BreakRunnable);
}
boolean foregroud = false;
try {
foregroud = new ForegroundCheckTask().execute(getApplication()).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
boolean background = isMyServiceRunning(TaxiNorrService.class);
if(foregroud == true && background == true && App.isAppForground()){
if(!App.isLoadingVisible()){
Intent intent = new Intent(TaxiNorrService.this, Loading_activity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}
}
poll_handler.postDelayed(this, 4000);
}
};
return Service.START_STICKY;
}
private void poll(double lat, double lon){
//Connected to API endpoint
}
...
...
#Override
public void onDestroy() {
if(r != null) {
if (r.isPlaying()) {
r.stop();
}
}
poll_handler.removeCallbacks(poll_runnable);
super.onDestroy();
}
}
I found the answer for my questions. The code written in the onStartCommand should be within onCreate function. This is because onCreate will execute when service starts first time, and onStartCommand will execute every time when you start the app. Please follow this topic,
Android - running a method periodically using postDelayed() call

How to run service for always in Android

In my application I want use service for get request to server.
I should run this service for always and not stop it!
I write below code in service, but just show for 5 time and when receive to 5 step. then not show Toast!
But I want always getData() and show Toast.
Service class :
public class NotifyService extends Service {
private static final String TAG = "HelloService";
private boolean isRunning = false;
#Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
isRunning = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand");
//Creating new thread for my service
//Always write your long running tasks in a separate thread, to avoid ANR
new Thread(new Runnable() {
#Override
public void run() {
//Your logic that service will perform will be placed here
//In this example we are just looping and waits for 5000 milliseconds in each loop.
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(5000);
} catch (Exception e) {
}
if (isRunning) {
ExploreSendData sendData = new ExploreSendData();
sendData.setPageIndex(1);
sendData.setPageSize(10);
sendData.setShowFollows(false);
sendData.setShowMovies(true);
sendData.setShowNews(true);
sendData.setShowReplies(false);
sendData.setShowSeries(true);
sendData.setShowSuggestions(false);
InterfaceApi api = ApiClient.getClient().create(InterfaceApi.class);
Call<ExploreResponse> call = api.getExplore(new SharedPrefrencesHandler(NotifyService.this)
.getFromShared(SharedPrefrencesKeys.TOKEN.name()), sendData);
call.enqueue(new Callback<ExploreResponse>() {
#Override
public void onResponse(Call<ExploreResponse> call, Response<ExploreResponse> response) {
if (response.body().getData() != null && response.body().getStatusCode() != 401
&& response.body().getStatusCode() != 402) {
Toast.makeText(NotifyService.this, "Test Show message ever 5second", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ExploreResponse> call, Throwable t) {
}
});
}
}
//Stop service once it finishes its task
stopSelf();
}
}).start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
Log.i(TAG, "Service onBind");
return null;
}
#Override
public void onDestroy() {
isRunning = false;
Log.i(TAG, "Service onDestroy");
}
}
I copy this service code from internet, but just show 5times. I want show always.
How can I edit my codes and fix it? Please help me. Thanks
The problem is not in the service, services start and continue living as long as the app is alive and android doesn't kill it. For an infinite loop replace the "for loop" with "While loop". The below loop doesn't end.
while (true) {
......
......
......
}

How to handle Location Listener updates inside a Service in Android?

I am working on an app that should get accurate user location continuously if user is inside a specific zone.
The location updates should be saved on a server (Parse.com) so other users can get the current location of the user.
The flow is:
Application onCreate -->
start Service with LocationListener -->
onLocationChanged -->
save new location on Parse.com -->
Parse.com Cloud afterSave method send push notification to users -->
other users get notifications via broadcast reciever -->
update user marker on map <--
Questions:
I am not sure about how to implement step 4, should I save the new location on parse inside the onLocationChanged method? should I pass it to a BroadcastReciever and save it on parse there? or should I pass it to a static method in my CurrentUser class that will perform the save on server?
I have noticed the requestLocationUpdates documentation says:
"This method is suited for the foreground use cases, more specifically
for requesting locations while being connected to LocationClient. For
background use cases, the PendingIntent version of the method is
recommended."
In my case, which method should I use?
What values should I use for getting almost real time location without consuming more than 5% of battery power per hour?
My Service Class:
public class UserTracker extends Service implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener, LocationListener{
static int GEOFENCE_STATUS;
final static int INSIDE_GEOFENCE = 9001, OUTSIDE_GEOFENCE = 9002;
static final int MINIMUM_ACCURACY = 26;
final static int GEOFENCE_RADIUS = 2000;
static final int NULL_LOCATION_ERROR = 7001;
static final int INSIDE_INTERVAL = 10000, INSIDE_FASTEST_INTERVAL = 1000, INSIDE_SMALLEST_DISPLACEMENT = 10;
static final int OUTSIDE_INTERVAL = 300000, OUTSIDE_FASTEST_INTERVAL = 60000, OUTSIDE_SMALLEST_DISPLACEMENT = 100;
static Location eventLocation;
LocationClient lc;
#Override
public void onCreate() {
super.onCreate();
eventLocation = new Location("Test");
lc = new LocationClient(getApplicationContext(), this, this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
double eventLat = intent.getDoubleExtra("Latitude", -1);
double eventLon = intent.getDoubleExtra("Longitude", -1);
if (eventLat == -1 || eventLon == -1) {
stopSelf();
return START_REDELIVER_INTENT;
}
eventLocation.setLatitude(eventLat);
eventLocation.setLongitude(eventLon);
lc.connect();
return START_STICKY;
}
public int getGeofenceStatus(Location currentLocation) {
if (currentLocation == null) {
return NULL_LOCATION_ERROR;
}
if (currentLocation.distanceTo(eventLocation) > GEOFENCE_RADIUS) {
Log.d(TAG, "User is outside geofence");
return OUTSIDE_GEOFENCE;
} else {
Log.d(TAG, "User is inside geofence");
return INSIDE_GEOFENCE;
}
}
public void requestLocationUpdates(int status) {
GEOFENCE_STATUS = status;
LocationRequest request = LocationRequest.create();
switch (status) {
case NULL_LOCATION_ERROR:
stopSelf();
break;
case INSIDE_GEOFENCE:
request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
request.setInterval(INSIDE_INTERVAL);
request.setFastestInterval(INSIDE_FASTEST_INTERVAL);
request.setSmallestDisplacement(INSIDE_SMALLEST_DISPLACEMENT);
break;
case OUTSIDE_GEOFENCE:
request.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
request.setInterval(OUTSIDE_INTERVAL);
request.setFastestInterval(OUTSIDE_FASTEST_INTERVAL);
request.setSmallestDisplacement(OUTSIDE_SMALLEST_DISPLACEMENT);
break;
}
lc.requestLocationUpdates(request, this);
}
#Override
public void onLocationChanged(Location location) {
int newStatus = getGeofenceStatus(location);
int accuracy = (int) location.getAccuracy();
String message = "Geofence status: " + newStatus +
"\nAccuracy: " + accuracy +
"\nDistance to event: " + location.distanceTo(eventLocation);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
if (newStatus == INSIDE_GEOFENCE && accuracy < MINIMUM_ACCURACY) {
Log.d(TAG, "Accuracy is good");
// do the save on server procees
}
if (GEOFENCE_STATUS != newStatus) {
requestLocationUpdates(newStatus);
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.d(TAG, "LocationClient connection failed: " + result.getErrorCode());
}
#Override
public void onConnected(Bundle arg0) {
Location currentLocation = lc.getLastLocation();
requestLocationUpdates(getGeofenceStatus(currentLocation));
}
#Override
public void onDisconnected() {
Log.d(TAG, "LocationClient disconnected");
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}

How to fix Service Instance Issue?

I am starting a service based on Alarm Manager in every 20 seconds which sends GPS data to my server.
The problem is my heap and allocated heap size goes on increasing. When I analysed the heap dump, I found the number of service instances is equal to the number of calls to startService(). How to avoid this issue?
public class SystemBootListener extends BroadcastReceiver {
// Restart service every 30 seconds
private static final long REPEAT_TIME = 1000 * 10;
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, StartLocationServiceAfterReboot.class);
PendingIntent pending = PendingIntent.getBroadcast(context, 0, PendingIntent.FLAG_UPDATE_CURRENT);
// Start 20 seconds after boot completed - so that all providers are initialized by then
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 20);
// Trigger every 10 seconds
// InexactRepeating allows Android to optimize the energy consumption
AlarmManager service = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
service.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), REPEAT_TIME, pending);
}
}
public class StartLocationServiceAfterReboot extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(AppSettings.isRouteConfigured(context)){
AppSettings.setServiceRunning(context, Boolean.TRUE);
Intent service = new Intent(context, GPSComputationService.class);
context.startService(service);
}
}
}
public class GPSComputationService extends Service {
private static final int MAX_TIME_TO_FETCH_NEW_LOCATION = 8000;
private final IBinder mBinder = new ServiceBinder();
private Timer timerToFetchLocInfoFromProviders = null;
private LocationManager locationManager = null;
private boolean gpsProviderEnabled=false;
private boolean networkProviderEnabled=false;
private int numberOfSatellites = 0;
private GPSData bestKnownLocation = new GPSData();
private TCPWriter tcpWriter ;
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
tcpWriter= new TCPWriter(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
/*tcpWriter= new TCPWriter(this);*/
computeBestLocation();
return Service.START_STICKY;
}
private void stopGPSComputationService(){
stopSelf();
}
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class ServiceBinder extends Binder {
public GPSComputationService getService() {
return GPSComputationService.this;
}
}
public GPSData getBestKnownLocation() {
return bestKnownLocation;
}
public void publishBestKnownLocation(GPSData bestKnownLocation) {
this.bestKnownLocation = bestKnownLocation;
sendBestKnownLocationToNMEAServer();
}
public void sendBestKnownLocationToNMEAServer(){
if(getBestKnownLocation() == null){
stopGPSComputationService();
return;
}
TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.getDeviceId();
NMEAData dataPacketToWrite = new NMEAData(
telephonyManager.getDeviceId(),
getBestKnownLocation().getLatitude(),
getBestKnownLocation().getLongitude(),
getBestKnownLocation().getTimeStamp(),
getBestKnownLocation().getSpeed(),
getBestKnownLocation().getNumberOfSatellites()
);
tcpWriter.sendMessage(NMEAServerTypes.MVT600,
dataPacketToWrite);
stopGPSComputationService();
}
public GPSData computeBestLocation() {
Log.d("#############GPSComputation Status", "Running.......");
try{
if(locationManager==null)
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
//Add status listener for satellite count
locationManager.addGpsStatusListener(gpsStatusListener);
Criteria criteria = new Criteria();
criteria.setSpeedRequired(true);
criteria.setBearingRequired(true);
List<String> providers = locationManager.getProviders(criteria, false);
//Capture if the GPS/Network providers have been disabled.
try{
gpsProviderEnabled=providers.contains(LocationManager.GPS_PROVIDER) &&
locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}catch(Exception e){
}
try{
networkProviderEnabled=providers.contains(LocationManager.NETWORK_PROVIDER) &&
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}catch(Exception e){
}
if(!gpsProviderEnabled && !networkProviderEnabled)
return null;
if(gpsProviderEnabled)
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if(networkProviderEnabled)
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
timerToFetchLocInfoFromProviders=new Timer();
timerToFetchLocInfoFromProviders.schedule(new GetLastKnownGoodLocation(), MAX_TIME_TO_FETCH_NEW_LOCATION);
locationManager.removeGpsStatusListener(gpsStatusListener);
//Finally store the data in backend Service
return getBestKnownLocation() ;
}catch(Exception e){
return null;
}
}
LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location) {
timerToFetchLocInfoFromProviders.cancel();
publishBestKnownLocation(extractAllGeoInfFromLocation(location));
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerNetwork);
locationManager.removeGpsStatusListener(gpsStatusListener);
gpsStatusListener = null;
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
//listen for gps status changes to capture number of satellites.
GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {
#Override
public void onGpsStatusChanged(int event) {
if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS || event == GpsStatus.GPS_EVENT_FIRST_FIX) {
GpsStatus status = locationManager.getGpsStatus(null);
Iterable<GpsSatellite> sats = status.getSatellites();
// Check number of satellites in list to determine fix state
int tempNumberOfSatellites = 0;
for (GpsSatellite sat : sats) {
if(sat.usedInFix())
tempNumberOfSatellites++;
}
numberOfSatellites = tempNumberOfSatellites;
}
}
};
LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location) {
timerToFetchLocInfoFromProviders.cancel();
publishBestKnownLocation(extractAllGeoInfFromLocation(location));
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerGps);
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
class GetLastKnownGoodLocation extends TimerTask {
#Override
public void run() {
locationManager.removeUpdates(locationListenerGps);
locationManager.removeUpdates(locationListenerNetwork);
Location bestKnownNetworkLocation = null, bestKnownGPSLocation=null;
if(gpsProviderEnabled)
bestKnownGPSLocation=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if(networkProviderEnabled)
bestKnownNetworkLocation=locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if(bestKnownGPSLocation!=null && bestKnownNetworkLocation!=null){
if(bestKnownGPSLocation.getTime()>bestKnownNetworkLocation.getTime())
publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownGPSLocation));
else
publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownNetworkLocation));
return;
}
if(bestKnownGPSLocation!=null){
publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownGPSLocation));
return;
}
if(bestKnownNetworkLocation!=null){
publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownNetworkLocation));
return;
}
AppLog.logWarningMsg("Bad luck-NO BEST LOCATION AVAILABLE");
publishBestKnownLocation(null);
}
}
private GPSData extractAllGeoInfFromLocation(Location location){
bestKnownLocation = new GPSData();
bestKnownLocation.setLatitude(location.getLatitude());
bestKnownLocation.setLongitude(location.getLongitude());
bestKnownLocation.setTimeStamp(location.getTime());
bestKnownLocation.setSpeed(location.getSpeed()*3.8);
bestKnownLocation.setNumberOfSatellites(numberOfSatellites);
return bestKnownLocation;
}
}
There is only one instance of service. As per the document
Multiple calls to Context.startService() do result in multiple corresponding calls to onStartCommand()),
But only one service instance can exist.
On startService(), the Android system calls the service's onStartCommand() method. If the service is not already running, the system first calls onCreate(), then calls onStartCommand().
The only thing that can create this kind of scenario is that you have some kind of memory leak.
Your service did it's work and stopped but didn't garbage collected. it probably happen few times and that is why you see many instances of it.
It's hard to find memory leaks but i would suggest you to start from the listeners. check if you unregistered them at the right time.
This link can help you to detect the leak:
https://developer.android.com/studio/profile/am-memory.html
Some tips to improve and simplify your code:
You want to use one shot service to report GPS coordinates. For this purpose IntentService is much better and it runs in a background thread by design.
https://developer.android.com/training/run-background-service/create-service
Use PendingIntent.getService() instead of call StartLocationServiceAfterReboot which just launch other Android component. You can do that immediately. You save one step.
https://developer.android.com/reference/android/app/PendingIntent.html#getService(android.content.Context,%2520int,%2520android.content.Intent,%2520int)
Every time you use a resource (like GPS, Sensor, etc...) you have to also write the release part. As I see, you register listeners to GPS Service but never release (unregister) them.
What does AppSettings.setServiceRunning(context, Boolean.TRUE);? My guess you save this into SharedPreference. This can be compromised when app force-stopped or device restarted or suddenly shut-down. Maybe better way this https://stackoverflow.com/a/5921190/5823014
Avoid to use static on Context, Activity, Service, BroadcastReceiver, Application instance. I'm not see in your code snippet, just a general advice to prevent memory-leaks.

How can I pass ApplicationContext into the function in a new Thread()?

I need to get location information about GPS location every 30 seconds in an infinity loop and send in to a server via HTTP-request. Endless cycle if GPS scanning should be stopped If i get an appropriate response from the server. Service is called DataTransferService, gps scanner is called GPSTracker for this and service . The problem is that I can't get a proper Context for my GPSTracker in my new Thread(new Runnable()).
If i create a ThreadHandler my MainActivity will freeze. In addition, context is also null even if I'm initializing in my service to use later.
Here is my DataTransferService.java
public class DataTransferService extends Service {
final static String LOG_TAG = "---===> service";
private boolean isRunning = false;
private GPSTracker gps;
private double lat;
private double lng;
public void onCreate() {
super.onCreate();
Log.d(LOG_TAG, "onCreate");
}
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(LOG_TAG, "onStartCommand");
if (!isRunning) {
StartLocationService();
isRunning = true;
}
return super.onStartCommand(intent, flags, startId);
}
public void onDestroy() {
isRunning = false;
super.onDestroy();
Log.d(LOG_TAG, "onDestroy");
}
public IBinder onBind(Intent intent) {
Log.d(LOG_TAG, "onBind");
return null;
}
private void StartLocationService(final String login, final String password) {
Thread thread = new Thread(new Runnable() {
public void run() {
Log.d(LOG_TAG, "StartLocationService() started");
while (true) {
//CHECK IF SERVICE IS RUNNING
if (!isRunning) {
stopSelf();
break;
}
//HERE IS THE PROBLEM <----------------
gps = new GPSTracker(getApplicationContext());
//GETTING GPS INFO
if(gps.canGetLocation()){
lat = gps.getLatitude();
lng = gps.getLongitude();
}else{
gps.showSettingsAlert();
}
try {
Log.d(LOG_TAG, String.format("location is: %f; %f", lat, lng));
//i wanted to send HTTP request to the server here with the gps coordinates
} catch (MalformedURLException e) {
e.printStackTrace();
}
//SERVICE DELAY
try {
TimeUnit.SECONDS.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
}
}
As I wanted to stop the endless loop when user presses "Stop" button I've created bool variable which indicated if the cycle should bee countinued or stopped.
UPDATE:
I added some debug outputs(before my Thread() and inside It) to determine if getApplicationContext() result isreally different and I found out, that all the objects are equal.
I used Log.d(LOG_TAG, getApplicationContext().toString()); before the Thread() and Log.d(LOG_TAG, mApplication.getInstance().getApplicationContext().toString()); inside the Thread(), where mApplication - is my singleton.
Results:
D/---===> service(7264): com.my.program.MyApplication#40ce3ee0
D/---===> service(7264): StartLocationService() started
D/---===> service(7264): com.my.program.MyApplication#40ce3ee0
Here is my GPSTracker.java if you are interested in it: http://pastebin.com/p6e3PGzD
Have you checked why your Activity will be frozen if you use HandlerThread? You can also create a Handler out of your thread, and send data via handler within your thread.
How can I pass ApplicationContext into the function in a new Thread()
You don't need to pass application context as you can access it from anywhere by
Defining android Application class in your codebase.
Just google "define application class android example"
http://developer.android.com/reference/android/app/Application.html
http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/
MyApplication.instance.getApplicationContext();
should be what you want. (where instance will be the singleton object you will define)

Categories

Resources