AsynchTask:Only one Looper may be created per thre

2019-08-30 02:34发布

问题:

My app crashing on every 4-5th call. It's showing me following exception.

10-14 14:00:30.651: E/AndroidRuntime(25035): FATAL EXCEPTION: AsyncTask #1
10-14 14:00:30.651: E/AndroidRuntime(25035): java.lang.RuntimeException: An error occured while executing doInBackground()
10-14 14:00:30.651: E/AndroidRuntime(25035):    at android.os.AsyncTask$3.done(AsyncTask.java:299)
10-14 14:00:30.651: E/AndroidRuntime(25035):    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
10-14 14:00:30.651: E/AndroidRuntime(25035):    at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
10-14 14:00:30.651: E/AndroidRuntime(25035):    at java.util.concurrent.FutureTask.run(FutureTask.java:239)
10-14 14:00:30.651: E/AndroidRuntime(25035):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
10-14 14:00:30.651: E/AndroidRuntime(25035):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
10-14 14:00:30.651: E/AndroidRuntime(25035):    at java.lang.Thread.run(Thread.java:838)
10-14 14:00:30.651: E/AndroidRuntime(25035): Caused by: java.lang.RuntimeException: Only one Looper may be created per thread
10-14 14:00:30.651: E/AndroidRuntime(25035):    at android.os.Looper.prepare(Looper.java:80)
10-14 14:00:30.651: E/AndroidRuntime(25035):    at android.os.Looper.prepare(Looper.java:75)
10-14 14:00:30.651: E/AndroidRuntime(25035):    at com..SplashActivity$LocationUpdator.doInBackground(SplashActivity.java:118)
10-14 14:00:30.651: E/AndroidRuntime(25035):    at com..SplashActivity$LocationUpdator.doInBackground(SplashActivity.java:1)
10-14 14:00:30.651: E/AndroidRuntime(25035):    at android.os.AsyncTask$2.call(AsyncTask.java:287)
10-14 14:00:30.651: E/AndroidRuntime(25035):    at java.util.concurrent.FutureTask.run(FutureTask.java:234)  

Here is my code.

public class LocationUpdator extends AsyncTask<Void, Void, Location> {
 Location location123 = null;



@Override
protected Location doInBackground(Void... arg0) {

    Looper.prepare();
    mThreadLooper = Looper.myLooper();          
    locationListener = new LocationListener() 
     {
     private String subLocality;
    @Override 
     public void onLocationChanged(Location location1) { 


         if(mThreadLooper != null)
            mThreadLooper.quit();
         //Stopping Request for Location
         if(manager!=null)
             manager.removeUpdates(locationListener);
     } 

    String status="success";


        if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            // if GPS provider is not enable then popup alertbox
            buildAlertMessageNoGps();
        } else {        
            // if gps is one then start searching                    
            status = "networkandgps";
            manager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000,1000,  locationListener); 
        }
    }

        manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        Log.i("TEST","Starting Network Provider");
        manager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, 10,locationListener);
        if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            //buildAlertMessageNoGps();
            ;
        } else {
            manager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 100000,100000,locationListener);               
        }
    } else {           

        manager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, 10,locationListener);            
    }

     Looper.loop();
    return location123;
}

@Override
protected void onPostExecute(Location result) {


    //progressDialog.dismiss();
    if(result!=null)
    {               
        Log.i("TESTING SPLASH","Lat3 "+userLocationLat);
        Log.i("TESTING SPLASH ","Long3 "+userLocationlong);

        startApplication();         

    }           

} }

I also try to quit loop in onstop method. but not helpful. I know it weird to use looper in Asynch task but is there any another way to use location listener inside Asynch Task's doInBackground method.

Please give me hint why i am getting this error.

回答1:

it's crashing because the threads of AsyncTask are used as a ThreadPool (that means it's the same 4 or 5 threads used and re-used. Said that the 1st part of the answer is:

No! You cannot use a Looper inside a AsyncTask because Only one Looper may be created per thread

On second thought, why are you using this Looper anyway? It is not doing anything in your code. If you believe that because of it, the Listener is being called in the background thread, I have bad news. It is not! The listener will be called in whichever thread it wants to call, normally that is the UI-Thread. If you want to avoid long running processes (such as network) in the UI thread, you should start a new thread (or a new AsyncTask) from the public void onLocationChanged(Location) method. Putting the Listener code inside the protected Location doInBackground(Void... arg0) is only making your code very confusing to read with no difference in actual execution.

I hope it helps.

edit:

in Android 4.0 (or 3.0, not sure) and up it's a SingleThreadPool, which makes this mess with Loopers a bit more tight.