user8550883
user8550883

Reputation: 83

Is it possible to Fetch user location from a Worker class?

I have to schedule a work to fetch user current location and update to server in a given interval (Even the app is not running).

I am trying to WorkManagerAPI to implement the functionality. Is it possible to fetch the current location of the user from the doWork() method ?

locationManager.requestLocationUpdates(
    provider, timeInterval, travelDistance, locationListener
);

When I request Location updates from the doWork() it throws below error.

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

Upvotes: 4

Views: 1086

Answers (1)

Tony
Tony

Reputation: 2451

As per my understanding, when implementing LocationManager.requestLocationUpdates() on a Worker thread, the call is being made on a non-UI, background thread created by WorkManager. LocationManager.requestLocationUpdates() is an asynchronous call possibly on another background thread. To handle the callbacks defined by the LocationListener, the calling thread must stay alive. Thats why the exception says,

Can't create handler inside thread that has not called Looper.prepare()

Check the code snippet below. Please consider this as pseudocode, I haven't tested this piece of code.

public class LocationWorker extends Worker {

    String LOG_TAG = "LocationWorker";
    private Context mContext;
    private MyHandlerThread mHandlerThread;

    public LocationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
        mContext = context;
    }

    @NonNull
    @Override
    public Result doWork() {
        Log.d(LOG_TAG, "doWork");

        mHandlerThread = new MyHandlerThread("MY_THREAD");
        mHandlerThread.start();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {

                LocationManager locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
                String bestProvider = locationManager.getBestProvider(new Criteria(), true);

                boolean permission = false;
                if (PermissionChecker.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
                        PermissionChecker.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                    Log.e(LOG_TAG, "This app requires ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permissions.");
                    permission = true;
                }

                Log.d(LOG_TAG, "permission: "+permission);
                Log.d(LOG_TAG, "bestProvider: "+bestProvider);

                if (permission && bestProvider != null) {

                    MyLocationListener locListener = new MyLocationListener();
                    locationManager.requestLocationUpdates(bestProvider, 500, 1, locListener, mHandlerThread.getLooper());
                }
            }
        };

        mHandlerThread.post(runnable);

        return Result.success();
    }


    class MyHandlerThread extends HandlerThread {

        Handler mHandler;

        MyHandlerThread(String name) {
            super(name);
        }

        @Override
        protected void onLooperPrepared() {
            Looper looper = getLooper();
            if (looper != null)
                mHandler = new Handler(looper);
        }

        void post(Runnable runnable) {
            if (mHandler != null)
                mHandler.post(runnable);
        }
    }

    class MyLocationListener implements LocationListener
    {
        @Override
        public void onLocationChanged(final Location loc)
        {
            Log.d(LOG_TAG, "Location changed: " + loc.getLatitude() +","+ loc.getLongitude());
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras)
        {
            Log.d(LOG_TAG, "onStatusChanged");
        }

        @Override
        public void onProviderDisabled(String provider)
        {
            Log.d(LOG_TAG, "onProviderDisabled");
        }

        @Override
        public void onProviderEnabled(String provider)
        {
            Log.d(LOG_TAG, "onProviderEnabled");
        }
    }
}

Upvotes: 1

Related Questions