2011-03-03 120 views
11

此问题使我发疯。我错过了一些关于如何在活动中创建的新线程中处理长操作以及如何在长操作完成后修改视图组件(如文本等)的基本知识但非常重要的知识。活动泄露了原本在此处添加的窗口[email protected]

首先,让我告诉你我的代码的部分地方发生此问题:

mProgressDialog = ProgressDialog.show(mContext, "Tripplanner", "please wait...", true, false); 
connectAndGetRoute(); 


private void connectAndGetRoute(){ 

    new Thread(){ 
     @Override 
     public void run() { 
      try { 
      if(!connectTo9292ov()) return;// conncetto9292ov() connects to a website, parses the reasult into an arraylist. The arraylist contains route. 

      } catch(UnknownHostException e){ 
       Toast.makeText(mContext, "failed to connect to server", Toast.LENGTH_LONG).show(); 
      }catch (ClientProtocolException e) { 
       Toast.makeText(mContext, "failed to connect to server", Toast.LENGTH_LONG).show();     
     } catch (IOException e) { 
       Toast.makeText(mContext, "failed to connect to server", Toast.LENGTH_LONG).show(); 
      } 

      handler.post(runConnection); 
     } 

    }.start(); 

    handler = new Handler(); 
    runConnection = new Runnable(){ 
     @Override 
     public void run() { 
      mProgressDialog.dismiss(); 
      showOnScreen(); 
     } 
    }; 
} 

,这是我得到的错误:

ERROR/WindowManager(8297): Activity mp.tripplanner.OvPlanner has leaked window [email protected] that was originally added here 
ERROR/WindowManager(8297): android.view.WindowLeaked: Activity mp.tripplanner.OvPlanner has leaked window [email protected] that was originally added here 
ERROR/WindowManager(8297): at android.view.ViewRoot.<init>(ViewRoot.java:251) 
ERROR/WindowManager(8297): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148) 
ERROR/WindowManager(8297): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91) 
ERROR/WindowManager(8297): at android.view.Window$LocalWindowManager.addView(Window.java:424) 
ERROR/WindowManager(8297): at android.app.Dialog.show(Dialog.java:241) 
ERROR/WindowManager(8297): at android.app.ProgressDialog.show(ProgressDialog.java:107) 
ERROR/WindowManager(8297): at android.app.ProgressDialog.show(ProgressDialog.java:95) 
ERROR/WindowManager(8297): at mp.tripplanner.OvPlanner$3.onClick(OvPlanner.java:351) 
ERROR/WindowManager(8297): at android.view.View.performClick(View.java:2408) 
ERROR/WindowManager(8297): at android.view.View$PerformClick.run(View.java:8817) 
ERROR/WindowManager(8297): at android.os.Handler.handleCallback(Handler.java:587) 
ERROR/WindowManager(8297): at android.os.Handler.dispatchMessage(Handler.java:92) 
ERROR/WindowManager(8297): at android.os.Looper.loop(Looper.java:144) 
ERROR/WindowManager(8297): at android.app.ActivityThread.main(ActivityThread.java:4937) 
ERROR/WindowManager(8297): at java.lang.reflect.Method.invokeNative(Native Method) 
ERROR/WindowManager(8297): at java.lang.reflect.Method.invoke(Method.java:521) 
ERROR/WindowManager(8297): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) 
ERROR/WindowManager(8297): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) 
ERROR/WindowManager(8297): at dalvik.system.NativeStart.main(Native Method) 

但另一条错误消息被写入日志之前的那个,这是:

ERROR/AndroidRuntime(8297): FATAL EXCEPTION: Thread-9 
ERROR/AndroidRuntime(8297): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 
ERROR/AndroidRuntime(8297): at android.os.Handler.<init>(Handler.java:121) 
ERROR/AndroidRuntime(8297): at android.widget.Toast.<init>(Toast.java:68) 
ERROR/AndroidRuntime(8297): at android.widget.Toast.makeText(Toast.java:231) 
ERROR/AndroidRuntime(8297): at mp.tripplanner.OvPlanner$4.run(OvPlanner.java:371) 

谢谢你的帮忙。

回答

4

需要在您的UI线程中创建您的Handler,以便它能够更新UI。 我会再使用sendMessage方法处理程序,而不是发布可运行:

private static final int HANDLER_MESSAGE_ERROR = 0; 
private static final int HANDLER_MESSAGE_COMPLETED = 1; 
... 
private void connectAndGetRoute(){ 
    new Thread(){ 
     @Override 
     public void run() { 
      try { 
       if(!connectTo9292ov()) return; 

      } catch(UnknownHostException e){ 
       sendMessage(HANDLER_MESSAGE_ERROR); 
      } catch (ClientProtocolException e) { 
       sendMessage(HANDLER_MESSAGE_ERROR); 
      } catch (IOException e) { 
       sendMessage(HANDLER_MESSAGE_ERROR); 
      } finally { 
       sendMessage(HANDLER_MESSAGE_COMPLETED); 
      } 
     } 
     private void sendMessage(int what){ 
      Message msg = Message.obtain(); 
      msg.what = what; 
      mHandler.sendMessage(msg); 
     } 
    }.start(); 

} 
... 
private Handler mHandler = new Handler(){ 
    @Override 
    public void handleMessage(Message msg) { 
     switch(msg.what){ 
     case HANDLER_MESSAGE_ERROR: 
      Toast.makeText(mContext, "failed to connect to server", Toast.LENGTH_LONG).show(); 
      break; 
     case HANDLER_MESSAGE_COMPLETED: 
      mProgressDialog.dismiss(); 
      showOnScreen(); 
      break; 
     default: 
      Log.w("MyTag","Warning: message type \""+msg.what+"\" not supported"); 
     } 
    } 
} 
+1

Thaks很多,这解决了这个问题。我只是想知道你是否推荐使用Handler的sendMessage而不是发布runnable? – mnish 2011-03-03 16:14:22

+1

@mnish两种方法都应该可以工作,我只是觉得跟踪你的UI更新更容易,如果他们都在一个地方。使用'sendMessage'很容易看出责任的分离,所以我觉得调试更容易。 – 2011-03-03 17:56:38

+0

清除谢谢! – mnish 2011-03-03 19:21:37

1

只是一个快速的想法。

我想,这是你在线程中的吐司消息。尝试将它们评论出来。

如果你仍然想显示消息,请保存你的线程的状态并在你的处理程序中处理它。征集你的处理器从finally块

mProgressDialog = ProgressDialog.show(mContext, "Tripplanner", "please wait...", true, false); 
connectAndGetRoute(); 


private void connectAndGetRoute(){ 

    new Thread(){ 
     @Override 
     public void run() { 
      try { 
      if(!connectTo9292ov()) return;// conncetto9292ov() connects to a website, parses the reasult into an arraylist. The arraylist contains route. 

      } catch(UnknownHostException e){ 
       // an int member of your activity 
       threadStatus = 404; 
       // Toast.makeText(mContext, "failed to connect to server", Toast.LENGTH_LONG).show(); 
      }catch (ClientProtocolException e) { 
       threadStatus = 404; 
       // Toast.makeText(mContext, "failed to connect to server", Toast.LENGTH_LONG).show();     
     } catch (IOException e) { 
       threadStatus = 404; 
       // Toast.makeText(mContext, "failed to connect to server", Toast.LENGTH_LONG).show(); 
      } 
      finally { 
      handler.post(runConnection);} 
     } 

    }.start(); 

    handler = new Handler(); 
    runConnection = new Runnable(){ 
     @Override 
     public void run() { 
      if (threadStatus == 404) { Toast.makeText(mContext, "failed to connect to server", Toast.LENGTH_LONG).show();} 
      else { 
      mProgressDialog.dismiss(); 
      showOnScreen();} 
     } 
    }; 
} 
+0

你猜对了,并猜测它太,但不知道,仍然不知道如何solveit。因为我不明白你提供的解决方案:D。你能否通过保存线程的状态告诉我你的意思,我该怎么做?我实际上需要更多解释你的解决方案:D。抱歉。 – mnish 2011-03-03 14:48:31

+1

我修改了你的代码。如果你问我原因,那么你不能从线程更新你的用户界面。你应该在外面做。 – Tima 2011-03-03 14:57:53

+0

,并看看@ Olsavage的回答 – Tima 2011-03-03 14:59:55

1

示例代码:

new Thread(new Runnable() {     
       @Override 
       public void run() { 
        doNotUIthings(); 
        updateUI.sendEmptyMessage(0); //Update ui in UI thread 
       } 
       private Handler updateUI = new Handler(){ 
        @Override 
        public void dispatchMessage(Message msg) { 
         super.dispatchMessage(msg); 
         updateUI(); 
        } 
       }; 
      }).start(); 

但我建议使用AsyncTask而不是Java线程。

+0

非常感谢。从来没有这个实际上。虽然我不知道这是如何工作的,但如果当前的问题再次出现,我肯定会考虑在未来使用它。但现在我会继续使用Dave.c提供的解决方案,因为它对我来说工作得很好。 – mnish 2011-03-03 16:19:45

相关问题