AsyncTask and Looper.prepare() error
Asked Answered
C

2

31

I have the following code

class OverlayTask extends AsyncTask<Void, Void, Void> {
    @Override
    public void onPreExecute() {

        if (sites != null) {
            myMapView.getOverlays().remove(sites);
            myMapView.invalidate();
            sites = null;
        }
    }

    @Override
    public Void doInBackground(Void... unused) {
            grabShipsWithLocation();
            return (null);
    }

    @Override
    public void onPostExecute(Void unused) {
        myMapView.getOverlays().add(sites);
        myMapView.invalidate();
        isLoading = false;
    }
}

That seems to work fine on a few test devices but I am seeing a lot of errors appearing on the dev console. I can't seem to work out why and where to put this Looper.prepare(). Is it needed?

java.lang.ExceptionInInitializerError
at com.test.appname.FinderMain$1.gotLocation(FinderMain.java:286)
at com.test.appname.MyLocation$GetLastLocation.run(MyLocation.java:89)
at java.util.Timer$TimerImpl.run(Timer.java:289)
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
at android.os.AsyncTask.<clinit>(AsyncTask.java:152)

As requested MyLocation.java

    class GetLastLocation extends TimerTask {
    @Override
    public void run() {
         lm.removeUpdates(locationListenerGps);
         lm.removeUpdates(locationListenerNetwork);

         Location net_loc=null, gps_loc=null;
         if(gps_enabled)
             gps_loc=lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
         if(network_enabled)
             net_loc=lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);

         //if there are both values use the latest one
         if(gps_loc!=null && net_loc!=null){
             if(gps_loc.getTime()>net_loc.getTime())
                 locationResult.gotLocation(gps_loc);
             else
                 locationResult.gotLocation(net_loc);
             return;
         }

         if(gps_loc!=null){
             locationResult.gotLocation(gps_loc); //Line 89
             return;
         }
         if(net_loc!=null){
             locationResult.gotLocation(net_loc);
             return;
         }
         locationResult.gotLocation(null);
    }
}
Coronagraph answered 15/11, 2010 at 19:18 Comment(4)
What does grabShipsWithLocation() do?Weird
What line is MyLocation.java:89? add a comment to your source.Screwworm
Are you creating/starting the AsyncTask from the main thread?Grenadier
Please add the gotLocation() method or at least the snippet which initializes the OverlayTask class.Omland
S
95

Long story:

AsyncTask internally uses a Handler. A handler basically allows you to post Runnables from another thread on the thread the handler was assigned to, which in the case of AsyncTask is always the thread from which it is called. This only works for threads that have a Looper prepared, though.

For more information see http://developer.android.com/reference/android/os/Handler.html

Short story:

Simply wrap every call to FinderMain$1.gotLocation or the creation of AsyncTask within it in a Runnable, and post it to a Handler bound to the UI thread, like this:

class GetLastLocation extends TimerTask {
    private Handler mHandler = new Handler(Looper.getMainLooper());

    @Override
    public void run() {
       // ...
       mHandler.post(new Runnable() {
          public void run() {
              locationResult.gotLocation(null);
          }
       });
       // ...
     }
}
Sapper answered 18/11, 2010 at 17:30 Comment(5)
Just the locationResult.gotLocation(null); in the new section or the whole lot above?Coronagraph
Or each locationResult.gotLocation(stuff) ??Coronagraph
All calls to gotLocation need to happen within the UI Thread, meaning in the Runnable as above. You can also wrap the whole section within it, but keep in mind that this might slow down your UI, if its execution takes too long. Alternatively, you can also wrap the AsyncTask creation within gotLocation in a Runnable like this.Sapper
That seems to work and I published an update, however when trying to wrap the locationResult.gotLocation(net_loc); it wants me to declare net_loc as final which then breaks the calls above itCoronagraph
Define net_loc as a member of GetLastLocation, or make it final and only assign it null in the else block of the initial if-clause, and not within the declarationSapper
S
18

I tried this...It worked,hope it will help you..

protected class Asyctast extends AsyncTask<String, Integer, Integer>
{

    @Override
    protected Integer doInBackground(String... params) {
        // TODO Auto-generated method stub


        Log.d("Asynctask", ""+params);  
Looper.prepare();   

         ImageThumbnailsActivity m = new ImageThumbnailsActivity();

            Toast.makeText(ImageThumbnailsActivity.this,""+params ,Toast.LENGTH_SHORT).show();
            final Dialog dialog_options = new Dialog(ImageThumbnailsActivity.this);
            dialog_options.setContentView(R.layout.option);
            dialog_options.show();
        Looper.loop();
        return null;
    }       
}
Savell answered 13/3, 2011 at 16:26 Comment(1)
It is a not good solution, cause Looper.loop() will blocked forever and Thread will never done. You should to use Looper.myLooper().quit() to avoid this. Except of that if you need to call Looper.prepare() from Thread - use Thread instead of AsyncTask.Mychal

© 2022 - 2024 — McMap. All rights reserved.