I have one Android Service. This Service launch one class for geolocation. This is the code.
public class Localizar implements LocationListener {
private LocationManager manejador;
private Context context;
private DBAdapter db;
public Localizar(Context context) {
this.context = context;
db = new DBAdapter(context);
}
public void start() {
manejador = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (manejador.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
manejador.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 500, 0, this);
}else {
}
}
public void stop() {
manejador.removeUpdates(this);
}
private void saveData(double longitude, double latitude) {
Toast.makeText(context, "G R A B A N D O D A T O S", Toast.LENGTH_LONG).show();
}
public void onLocationChanged(Location location) {
saveData(location.getLatitude(), location.getLongitude());
}
public void onProviderDisabled(String proveedor) {
}
public void onProviderEnabled(String proveedor) {
}
public void onStatusChanged(String arg0, int arg1, Bundle bundle) {
}
}
My problem is that the method onLocationChanged never executed. What have I done wrong ?
Thank you!
I tried it on another phone and it works correctly, maybe my phone is broken. I have a samsung galaxy DUOS.....
There is a lot reasons why you don't get onLocationChanged
If you run it in Service try add Looper.getMainLooper(), like:
manejador.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
500,
0,
this,
Looper.getMainLooper()
);
Related
onLocationChanged event is not fired with requestSingleUpdate.
It seems that it depends on the looper attached ex:
locManager.requestSingleUpdate("network",locListener,Looper.getMainLooper());
locManager.requestSingleUpdate("network",locListener,null);
locManager.requestSingleUpdate("network",locListener,Looper.myLooper());
are not giving the same results with the emulator and the device !
Questions
If requestSingleUpdate is called many times (with different providers), only the last query will be taken ?
requestSingleUpdate must be called on ui thread ? If not, there's a trick to call it outside ?
Complete Class :
public class LocationNew {
private Context context;
public LocationNew(Context context) {
this.context = context;
}
public void requestNew(Looper paramLooper){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int permissionLocation = ContextCompat.checkSelfPermission(DooodApp.getContext(), Manifest.permission.ACCESS_FINE_LOCATION);
if (permissionLocation != PackageManager.PERMISSION_GRANTED) {
return;
}
}
LocationManager locManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
List<String> listProv = locManager.getProviders(true);
for (String provTmp: listProv) {
locManager.requestSingleUpdate(provTmp,locListener,Looper.getMainLooper());
}
}
private LocationListener locListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
Toast.makeText(context, "New location from : " + location.getProvider(), Toast.LENGTH_SHORT).show();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Toast.makeText(context, "onStatusChanged" , Toast.LENGTH_SHORT).show();
}
#Override
public void onProviderEnabled(String provider) {
Toast.makeText(context, "onProviderEnabled" , Toast.LENGTH_SHORT).show();
}
#Override
public void onProviderDisabled(String provider) {
Toast.makeText(context, "onProviderDisabled" , Toast.LENGTH_SHORT).show();
}
};
}
Thank's to all.
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.
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);
}
}
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) {
}
}
I've implemented code that should return present location.
First the code:
public static double[] getLocation(Context context) {
double[] result;
lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
MyLocationListener ll = new MyLocationListener();
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, ll);
while(!hasLocation) { }
result = ll.getResult();
return result;
}
private static class MyLocationListener implements LocationListener {
double[] result = new double[2];
public double[] getResult() {
return result;
}
#Override
public void onLocationChanged(Location location) {
if(location.getAccuracy() != 0.0 && location.getAccuracy() < 100) {
result[0] = location.getLatitude();
result[1] = location.getLongitude();
hasLocation = true;
lm.removeUpdates(this);
}
}
#Override
public void onProviderDisabled(String provider) {}
#Override
public void onProviderEnabled(String provider) {}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
}
The problem is that all stopps on 'while' statement. WHen I've tried to debug this setting breakpoint on the first line in onLocationChanged() nothing happens, but Logcat was showing some logs like:
loc_eng_report_position: vertical_accuracy = 64.000000
DEBUG/libloc(1292): date:2011-08-11, time:10:51:03.372, raw_sec=1313052663, raw_sec2=1313052663,raw_msec=1313052663372
Any ideas?
The while(!hasLocation) {} is blocking your application from doing anything. You'll either need to deal with the location in the callback onLocationChanged, or you'll need to start the location manager a lot earlier and hope that you have a result by the time you need it. You can't busy-wait for the answer.