Get Current Location From Android Background Service Issue - android

I want to develop location based reminder app. Therefore I want to use android service for get current location even app is not running. But I didn't do. I set timer in android service class but I don't know how to get current location in service class. What is the problem ? I got some error like this:
can't create handler inside thread that has not called looper.prepare()
public class TrackerService extends Service {
double latShared;
double lngShared;
double latService;
double lngService;
private LocationManager lm;
Timer timer;
Handler handler;
final static long TIME = 15000;
SharedPreferences mSharedPrefs;
SharedPreferences.Editor mPrefsEditor;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
mSharedPrefs = getSharedPreferences("locationXML", MODE_PRIVATE);
latShared = (double)mSharedPrefs.getFloat("lat", 0);
lngShared = (double)mSharedPrefs.getFloat("lng", 0);
timer = new Timer();
timer.schedule(new TimerTask(){
#Override
public void run(){
LocationUpdates();
}
},0,TIME);
}
public void LocationUpdates(){
locListener locList = new locListener();
lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locList);
}
#Override
public void onDestroy() {
//lm.removeUpdates(this);
timer.cancel();
}
public class locListener implements LocationListener{
#Override
public void onLocationChanged(Location location) {
latService = location.getLatitude();
lngService = location.getLongitude();
}
#Override
public void onProviderDisabled(String provider) {}
#Override
public void onProviderEnabled(String provider) {}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
}
}

LocationManager.requestLocationUpdates is supposed to run on UI thread as its sibling method defines. On the other hand TimerTask introduces a new thread to offload its execution.
However, if you are not using a new process for your service then simply call LocationUpdates() as below:
#Override
protected void onCreate() {
mSharedPrefs = getSharedPreferences("locationXML", MODE_PRIVATE);
latShared = (double)mSharedPrefs.getFloat("lat", 0);
lngShared = (double)mSharedPrefs.getFloat("lng", 0);
final Handler h = new Handler();
h.post(new Runnable() {
#Override
public void run() {
LocationUpdates();
h.postDelayed(this, TIME);
}
});
}
OR, if you don't want to use handler then simply upgrade your requestLocationUpdates as below:
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locList, getMainLooper());
In above case, getMainLooper() will dispatch your location updates from UI thread.

Related

I can't get location on Android real phone

public class LocationService extends Service {
private Handler mHandler = new Handler();
private Timer mTimer = null;
private int mCount = 0;
public static final long NOTIFY_INTERVAL = 10 * 1000;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
// cancel if already existed
if (mTimer != null) {
mTimer.cancel();
} else {
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
}
#Override
public void onDestroy() {
mTimer.cancel();
}
private class TimeDisplayTimerTask extends TimerTask implements LocationListener {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10 * 1000, 0,
TimeDisplayTimerTask.this);
}
});
}
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
if (location != null) {
Toast.makeText(getApplicationContext(), Double.toString(location.getLat(), Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), Double.toString(location.getLng(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "Cant Get Location", Toast.LENGTH_LONG).show();
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
}
This code work fine on emulator. I can get location every 10 second. But when I test it on real phone, I don't see anything appear at all. Is it anything wrong with this code? Please show me how to fix this.
Can you verify that your service is not being killed by the device on background?
(You can see this on Settings > Apps > Running tab > [Your app name] There should be a process count and service count there)
Android devices has it's own way if killing services on background. If that's the case, you should start your service on foreground. To prevent it from being killed.
How you ask? You should add this on start of your service:
Notification notification = new Notification();
startForeground(1, notification);
What is the notification you ask? This prompts the user when you're app is on background, you can substitute your toast with this. Here's a link related to its this. Check the accepted answer.
Android - implementing startForeground for a service?

Looper.prepare exception using LocationManager in external Service

I am getting the following exception when I try to use LocationManager within a custom class running in an external service:
*** Uncaught remote exception! (Exceptions are not yet supported across processes.)
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at android.location.LocationManager$GpsStatusListenerTransport$1.<init>(LocationManager.java:1464)
at android.location.LocationManager$GpsStatusListenerTransport.<init>(LocationManager.java:1464)
at android.location.LocationManager.addGpsStatusListener(LocationManager.java:1503)
at org.poseidon_project.contexts.hardware.GPSIndoorOutdoorContext.start(GPSIndoorOutdoorContext.java:97)
at org.poseidon_project.context.management.ContextManager.addObserverRequirement(ContextManager.java:97)
at org.poseidon_project.context.reasoner.ContextMapper.registerIndoorOutdoorsContext(ContextMapper.java:260)
at org.poseidon_project.context.reasoner.ContextMapper.registerContext(ContextMapper.java:197)
at org.poseidon_project.context.ContextReasonerCore.addContextRequirement(ContextReasonerCore.java:70)
at org.poseidon_project.context.ContextReasonerService$1.addContextRequirement(ContextReasonerService.java:74)
at org.poseidon_project.context.IContextReasoner$Stub.onTransact(IContextReasoner.java:74)
at android.os.Binder.execTransact(Binder.java:446)
Now, I have read many answer relating back to the use of Looper, with stuff like:
Looper.prepare;
mLocationManager.requestLocationUpdates(mProvider, mMinTime, mMinDistance, this, Looper.getMainLooper);
But this ends up not causing the Callback (onLocationChanged(Location location)) to be called when there is an update?
The class implements the LocationListener, which also invokes the LocatioManager methods:
public abstract class LocationContext extends ContextObserver implements LocationListener {
protected LocationManager mLocationManager;
private int mMinTime = 3000;
private int mMinDistance = 10;
private String mProvider = LocationManager.GPS_PROVIDER;
private String mIdealProvider = LocationManager.GPS_PROVIDER;
public LocationContext (Context c) {
super(c);
mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}
public LocationContext (Context c, ContextReceiver cr) {
super(c, cr);
mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}
public LocationContext (Context c, ContextReceiver cr, int minTime, int minDistance, String name) {
super(c, cr, name);
mMinTime = minTime;
mMinDistance = minDistance;
mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}
public LocationContext (Context c, ContextReceiver cr, int minTime, int minDistance, String provider, String name) {
super(c, cr, name);
mMinTime = minTime;
mMinDistance = minDistance;
mProvider = provider;
mIdealProvider = provider;
mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}
#Override
public boolean start() {
//new Thread(new Runnable() {
// #Override
// public void run() {
//Looper.prepare();
mLocationManager.requestLocationUpdates(mProvider, mMinTime, mMinDistance, this);
//handler.sendEmptyMessage(0);
//Looper.loop();
// }
//}).start();
mIsRunning = true;
//Looper.loop();
return true;
}
#Override
public boolean pause() {
return stop();
}
#Override
public boolean resume() {
return start();
}
#Override
public boolean stop() {
mLocationManager.removeUpdates(this);
mIsRunning = false;
return true;
}
#Override
public void onLocationChanged(Location location) {
checkContext(location);
}
protected abstract void checkContext(Location location);
#Override
public void onProviderDisabled(String provider) {
if (provider.equals(mIdealProvider)) {
mProvider = LocationManager.GPS_PROVIDER;
if (! mLocationManager.isProviderEnabled(mProvider)) {
Intent gpsOptionIntent = new Intent (android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.startActivity(gpsOptionIntent);
}
}
}
#Override
public void onProviderEnabled(String provider) {
if ((provider.equals(mIdealProvider)) && (! provider.equals(mProvider))) {
mLocationManager.removeUpdates(this);
mProvider = provider;
mLocationManager.requestLocationUpdates(mProvider, mMinTime, mMinDistance, this);
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
public int getMinTime() {
return mMinTime;
}
public void setMinTime(int mMinTime) {
this.mMinTime = mMinTime;
}
public int getMinDistance() {
return mMinDistance;
}
public void setMinDistance(int mMinDistance) {
this.mMinDistance = mMinDistance;
}
I don't really understand how to use the Looper in my situation. Can someone help? I understand the answer "run in UI thread" but this is a single service app, there is no UI, so I don't think I can do it in the UI thread?
****UPDATE*****Solution Found******
I believe I found a solution. The class in question was an abstract class, which I was extending by a few classes that did various Location based operations.
In the LocationContext abstract class I used:
mLocationManager.requestLocationUpdates(mProvider, mMinTime, mMinDistance,this, Looper.getMainLooper());
And in an implementation class (for example one for analysing GPS satellite status) I placed it in a new Thread:
new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
GPSIndoorOutdoorContext.super.start();
mLocationManager.addGpsStatusListener(gpsListener);
Looper.loop();
}
}).start();
mLocationManager.requestLocationUpdates(mProvider, mMinTime, mMinDistance, this);
is getting called from a NON UI Thread. Make sure you call your init or call your method in the UI Thread. You're probably initiating LocationContext or calling start method from a NON UI Thread, which you can't do. To request location updates, it must be called from the UI Thread.

running an script only for an specific time

I have a code for detecting location that I want to works only for 2 minutes.
when I fire start() method script must works almost for 2 minutes.
problem is in there that how run my script only for an specific time.
I used this code but don't running correct.
don't fire stop() method from in Timer().schedule()
public class a implements LocationListener{
private LocationManager locationManager;
private String provider;
private Location lastloc;
private Context _context;
public a(Context context){
_context = context;
}
public void start(){
locationManager = (LocationManager) _context.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 1, (LocationListener) this);
new Timer().schedule(
new TimerTask(){
public void run() {
stop();
}
}
,System.currentTimeMillis(), 2*60*1000);
}
public void stop(){
Log.d("states","stop");
locationManager.removeUpdates((LocationListener) this);
}
#Override
public void onLocationChanged(Location location) {
Log.d("states", "onLocationChanged()");
lastloc = location;
}
#Override
public void onProviderDisabled(String arg0) {
}
#Override
public void onProviderEnabled(String arg0) {
}
#Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
}
}
Check your code of Timer again. Usually, the Timer code should be like:
Timer.schedule(TimerTask,
delayTime); // delay a task before executed for the first time, in milliseconds
Because of your delayTime has been executed by using System.currentTimeMillis(), the System picks the current time in milliseconds since midnight, so that the TimerTask will be executed after millions millisecond.
Hence, use this code:
Timer timer = new Timer();
timer.schedule(new TimerTask(){
#Override
public void run() {
// do your thing here
}
}, 2*60*1000);
See this documentation about the type of Timer you created.
I finally solved my problem by using handlers.
read this page: Using Bundle Android to Exchange Data Between Threads
a.java
public class a implements LocationListener{
private LocationManager locationManager;
private String provider;
private Location lastloc;
private Context _context;
private Thread workingthread = null;
final Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
Log.d("states","return msg from timer2min");
if(msg.what==1){
stop();
}
super.handleMessage(msg);
}
};
public a(Context context){
_context = context;
}
public void start(){
locationManager = (LocationManager) _context.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 1, (LocationListener) this);
workingthread=new timer2min(mHandler);
workingthread.start();
}
public void stop(){
Log.d("states","stop");
locationManager.removeUpdates((LocationListener) this);
}
#Override
public void onLocationChanged(Location location) {
Log.d("states", "onLocationChanged()");
}
#Override
public void onProviderDisabled(String arg0) {
}
#Override
public void onProviderEnabled(String arg0) {
}
#Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
}
}
timer2min.java
public class timer2min extends Thread {
private Handler hd;
public timer2min(Handler msgHandler){
hd = msgHandler;
}
public void run() {
try {
Thread.sleep(2*60*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg = hd.obtainMessage();
msg.what = 1;
hd.sendMessage(msg);
}
}

Android LocationListener on Service with Thread

I´d like to implement a LocationListener in this way.
1 - Activity_first - Call LocationListener, but I have some spinner and this don´t respond when the LocationListener are onStart(). I´d like to implement with a Thread.
2 - When the onLocationChanged() in LocationListener gets called, I call Geocoder, and when the address is different than null, I save it on the shared preferences, and stop it.
Point 2, must be done in the background because the user might be in an Activity when I get the Geocoder's address (about 10 seconds, it depend on connection)
I was testing with IntentService, but of course, I doesn't work.
My Code
public class Carga_1 extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.carga_1);
// Todo Create Spinner, etc
startService(new Intent(Carga_1.this, LocationService2.class));
}
}
public class LocationService2 extends Service {
public static final String BROADCAST_ACTION = "Hello World";
//public LocationManager locationManager; testted
//public MyLocationListener listener; tested
public Location previousBestLocation = null;
Thread my_thread;
#Override
public IBinder onBind(Intent intent) {
Log.d("[GPS_coord]", "????");
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onStart(Intent intent, int startId) {
Runnable r = new Runnable() {
public void run() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
MyLocationListener listener = new MyLocationListener();
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, listener);
}
};
my_thread = new Thread(r);
my_thread.start();
}
#Override
public void onDestroy() {
super.onDestroy();
my_thread.stop();
}
private void get_address(double lat, double longi) {
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
List<Address> addresses;
try {
addresses = geocoder.getFromLocation(lat, longi, 1);
//SAVE ON SharedPrefereces
this.stopSelf();
}
catch (IOException e) {
Log.d("[GPS_geocoder]", "Decodificacion Erronea");
}
}
public class MyLocationListener implements LocationListener {
public void onLocationChanged(final Location loc) {
Log.i("GPS_Service", "Location changed");
Log.d("GPS_Service", String.valueOf(loc.getLatitude() + " : " + String.valueOf(loc.getLongitude())));
get_address(loc.getLatitude(), loc.getLongitude());
}
public void onProviderDisabled(String provider) {
Log.i("GPS_Service", "DES_habilitado");
}
public void onProviderEnabled(String provider) {
Log.i("GPS_Service", "Habilitado");
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}

turn on gps and using it

I have a class for get the user location.
If the GPS is off I turned it on and show the location, but it doesnt work.
this is the class:
public class UseGPS implements Runnable{
Activity activity;
Context context;
private ProgressDialog pd;
LocationManager mLocationManager;
Location mLocation;
MyLocationListener mLocationListener;
Location currentLocation = null;
public UseGPS(Activity Activity, Context Context){
this.activity = Activity;
this.context = Context;
}
public void getMyPos(){
DialogInterface.OnCancelListener dialogCancel = new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
Toast.makeText(activity,"no gps signal",Toast.LENGTH_LONG).show();
handler.sendEmptyMessage(0);
}
};
pd = ProgressDialog.show(activity,context.getString(R.string.looking_for), context.getString(R.string.gps_signal), true, true, dialogCancel);
writeSignalGPS();
}
private void setCurrentLocation(Location loc) {
currentLocation = loc;
}
private void writeSignalGPS() {
Thread thread = new Thread(this);
thread.start();
}
public void run() {
mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
Looper.prepare();
mLocationListener = new MyLocationListener();
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mLocationListener);
Looper.loop();
Looper.myLooper().quit();
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
pd.dismiss();
mLocationManager.removeUpdates(mLocationListener);
if (currentLocation!=null) {
Toast.makeText(activity,currentLocation.getLatitude(),Toast.LENGTH_LONG).show();
Toast.makeText(activity,currentLocation.getLongitude(),Toast.LENGTH_LONG).show();
}
}
};
private class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
if (loc != null) {
setCurrentLocation(loc);
handler.sendEmptyMessage(0);
}
}
#Override
public void onProviderDisabled(String provider) {
/*turn on GPS*/
Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE");
intent.putExtra("enabled", true);
context.sendBroadcast(intent);
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
}
The code works when the GPS is turned on, but it doesnt turn the gps on.
What can I do?
While launching time of your app, give one pop-up message with option to turn on the GPS by the user.
This pop-up button navigates to GPS setting in Setting for their user can turn on the GPS.
Here is the code snippet:
AlertDialog gpsonBuilder = new AlertDialog.Builder(Home_Activity.this);
gpsonBuilder.setTitle("Your Gps Provider is disabled please Enable it");
gpsonBuilder.setPositiveButton("ON",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}
});
gpsonBuilder.show();

Categories

Resources