AsyncTask和Looper.prepare()错误

31
我有以下代码。
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;
    }
}

这在几个测试设备上似乎运行良好,但我在开发控制台上看到了许多错误。我似乎无法确定为什么以及在哪里放置这个 Looper.prepare()。它是必需的吗?

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)

根据要求提供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);
    }
}

1
grabShipsWithLocation() 函数是做什么的? - Falmarri
1
MyLocation.java:89是哪一行?在你的源代码中添加注释。 - blindstuff
你是从主线程创建/启动AsyncTask吗? - gngr44
1
请添加 gotLocation() 方法或至少初始化 OverlayTask 类的代码片段。 - Draško Kokić
2个回答

95

长篇故事:

AsyncTask 在内部使用了一个 Handler。一个 handler 基本上允许你在另一个线程中通过 handler 分派 Runnables 到它所分配的线程上,而在 AsyncTask 的情况下,这个线程总是从调用它的线程中来的。虽然这仅适用于那些已经准备好了 Looper 的线程。

欲了解更多信息,请参见http://developer.android.com/reference/android/os/Handler.html

简短故事:

只需将对 FinderMain$1.gotLocation 或创建 AsyncTask 的每次调用包装在一个 Runnable 中,并将其发布到绑定到 UI 线程的 Handler 中即可,如下所示:

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);
          }
       });
       // ...
     }
}

只需要在新部分中的locationResult.gotLocation(null);还是整个以上部分都需要? - Lee Armstrong
还是每个locationResult.gotLocation(stuff)? - Lee Armstrong
所有对gotLocation的调用都需要在UI线程中进行,也就是在上面的Runnable中。你也可以将整个部分包装在其中,但请记住,如果执行时间过长,这可能会减慢您的UI。或者,您也可以像这样在gotLocation中将AsyncTask创建包装在一个Runnable中。 - Timo Ohr
似乎这个方法可以工作并且我已经发布了一个更新,但是当我尝试包装locationResult.gotLocation(net_loc)时,它要求我将net_loc声明为final,这会破坏其上面的调用。 - Lee Armstrong
将net_loc定义为GetLastLocation的成员,或者在初始if子句的else块中将其定义为final并仅分配null,并且不在声明中进行赋值。 - Timo Ohr

18

我尝试了这个...它有效了,希望能对你有所帮助。

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;
    }       
}

8
这不是一个好的解决方案,因为Looper.loop()会一直阻塞并且线程永远不会完成。你应该使用Looper.myLooper().quit()来避免这种情况。另外,如果你需要从线程中调用Looper.prepare(),请使用Thread而不是AsyncTask。 - Borg8

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接