0

I've got a service that instantiates a web server using com.koushikdutta.async.AsyncHttpServer. Inside a callback, I need to instantiate a class which is calling requestLocationUpdates on LocationManager. But this is causing an exception:

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

I'm trying to setup a looper/handler to get rid of this error, but I'm not exactly sure how to proceed. This example shows how to create a thread class which creates a handler, but not how to use it. In this answer which mistakenly claims you can't use a Handler but then provides a link to showing how to do that is some code which I have adapted to look like this:

Handler handler = new Handler();
final GPSListener gps;
handler.post(new Runnable() {
    @Override
    public void run() {
        gps = new GPSListener(ctx,ews);
    }
})

This code is in the callback in response to an HTTP request. But there is an immediate problem. I can't use the gps variable in the Runnable unless it is declared final. But if I declare it final outside the Runnable, then it tells me that I can't initialize it since it's final. But I can't initialize it outside the Runnable, because the whole point of putting it in the Runnable is to avoid the exception caused by trying to the constructor trying to call requestLocationUpdates instead a thread which has not called Looper.prepare(). Additionally, this gps variable also needs to be outside the Runnable because another callback (on connection close) needs to call another function on it to shut things down. Further, the variable has to be local to the callback, because it needs to separately instantiate a new object each time the callback is called.

I'm not sure the way I'm trying to set up the handler is even correct, and assuming it is, how can I get past the above issues?

Michael
  • 9,060
  • 14
  • 61
  • 123

2 Answers2

0

As I understood, you run Service from another thread, don't you? In order, to make it work you should call Looper.prepare() before your class instantiation.

Mike
  • 2,547
  • 3
  • 16
  • 30
  • I create an Intent in the Sctivity with my service class, then call startService() with that Intent. After this my service gets foregrounded, so it's entirely possible that it still runs but the activity goes away. – Michael Jan 10 '20 at 01:38
  • my Service is already creating a Handler thread too... but this is only handling intents to the service which invoke onStart or onStartCommand... I'm not sure what thread the HTTP callback is occurring in. – Michael Jan 10 '20 at 01:47
  • You should consider using HandlerThread instead - https://developer.android.com/reference/android/os/HandlerThread. Or you might want to use IntentService which already has already such behavior with asynchronous handling of the incoming Intents: https://developer.android.com/reference/android/app/IntentService – Mike Jan 10 '20 at 11:04
0

AndroidSync is single-threaded, so setting up a looper on the thread that you instantiate it isn't going to work anyway. In the callback, create a new thread, prepare a looper, and then after you start the GPS engine, run the loop:

final Thread t = new Thread() {
    @Override
    public void run() {
        Looper.prepare();
        gps.start((long)mint,(float)mind,sat!=0);
        Looper.loop();
     }
};
Michael
  • 9,060
  • 14
  • 61
  • 123