Search code examples
androidrunnablelocationmanagerandroid-handler

Android: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()


I am making an android app where I am trying to get location using location manager and then I push that location to a server. When I try to do this I am getting the following error.

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$ListenerTransport$1.<init>(LocationManager.java:223)
            at android.location.LocationManager$ListenerTransport.<init>(LocationManager.java:223)
            at android.location.LocationManager.wrapListener(LocationManager.java:851)
            at android.location.LocationManager.requestLocationUpdates(LocationManager.java:864)
            at android.location.LocationManager.requestLocationUpdates(LocationManager.java:459)
            at com.pickingo.fe.services.gps.AppLocationService.getLocation(AppLocationService.java:30)
            at com.pickingo.fe.gps.CurrentLocationPusher.run(CurrentLocationPusher.java:60)
            at java.lang.Thread.run(Thread.java:818)

This is my appLocationService

public class AppLocationService extends Service implements LocationListener {

    protected LocationManager locationManager;
    Location location;

    private static final long MIN_DISTANCE_FOR_UPDATE = 50;
    private static final long MIN_TIME_FOR_UPDATE = 1000*60*2;

    public AppLocationService(Context context) {
        locationManager = (LocationManager) context
                .getSystemService(LOCATION_SERVICE);
    }

    public Location getLocation(String provider) {
        if (locationManager.isProviderEnabled(provider)) {
            locationManager.requestLocationUpdates(provider,
                    MIN_TIME_FOR_UPDATE, MIN_DISTANCE_FOR_UPDATE, this);
            if (locationManager != null) {
                location = locationManager.getLastKnownLocation(provider);
                return location;
            }
        }
        return null;
    }

    @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 IBinder onBind(Intent arg0) {
        return null;
    }

}

This is the code I use to push the location after getting the location from the LocationManager.

public class CurrentLocationPusher implements Runnable {


    private static CurrentLocationPusher _singleInstance;

    private CurrentLocationPusher() {
        this.apiClient = ApiClient.getInstance();
        this.appLocationService = new AppLocationService(appContext);
        this.runningThread = new Thread(this);
    }

    public static CurrentLocationPusher getInstance() {
        if (_singleInstance == null)
            synchronized (CurrentLocationPusher.class) {
                if (_singleInstance == null)
                    _singleInstance = new CurrentLocationPusher();
            }
        return _singleInstance;
    }

    private boolean isStopThread = false;

    public static final long ONE_MINUTE = 60 * 1000;

    private static Context appContext;

    private AppLocationService appLocationService;

    private ApiClient apiClient;
    private Thread runningThread;


    public static void init(Context applicationContext) {

        appContext = applicationContext;
    }

    @Override
    public void run() {

        Location location = appLocationService
                .getLocation(LocationManager.GPS_PROVIDER);
        while (!isStopThread) {
            try {
                if (location != null)
                    if (CommonUtils.isActiveToInternet(appContext))
                        apiClient.getApi(appContext).pushLocation(String.valueOf(location.getLatitude()),
                                String.valueOf(location.getLongitude()),String.valueOf(System.currentTimeMillis()),
                                String.valueOf(location.getAccuracy()));
                Thread.sleep(ONE_MINUTE);
            } catch (InterruptedException e) {

            } catch (Exception e) {
                Log.e(PickingoConstant.TAG, "error" + e.getMessage());
            }
        }

    }


    public void startPushingLocation() {
        if (this.runningThread.getState() == Thread.State.NEW) {
            runningThread.start();
            isStopThread = false;
        } else if (this.runningThread.getState() == Thread.State.TERMINATED) {
            (runningThread = new Thread(this)).start();
            isStopThread = false;
        } else if (this.runningThread.getState() == Thread.State.RUNNABLE) {
            return;
        }

    }

    public void stopPushingLocation() {
        isStopThread = true;
    }
}

I am getting error at the following line in CurrentLocationPusher

            .getLocation(LocationManager.GPS_PROVIDER);

If someone could give a hint or some assistance I would really appreciate it. Thanks in advance !!


Solution

  • As pointed out by Michael adding this code at starting of my run() method worked.

    if (Looper.myLooper() == null) {
                Looper.prepare();
            }