2012-06-27 86 views
4

我在執行postexecute()上的AlertDialog時遇到問題。拋出這個異常 引起:java.lang.RuntimeException:無法在未調用Looper.prepare() 的線程內創建處理程序或者,當我放入AlertDialog.Builder時,它只是不起作用 請幫助。 同樣在輸入錯誤密碼的情況下,該過程終止。我怎麼能叫的情況下敬酒方法是將USENAME或密碼無效 下面的代碼片段無法在doInbackground()方法中執行AlertDialog

public void Login() { 

    // Toast.makeText(getBaseContext(), pass.getText() + " " 
    // +user.getText(), 
    // Toast.LENGTH_SHORT).show(); 

    String url = "http://107.20.195.151/mcast_ws/" + "?user=" 
      + user.getText().toString() + "&password=" 
      + pass.getText().toString(); 

    result = getHttpResponse(url); 
} 


String result; 
private String getHttpResponse(String location) { 
    result = ""; 
    URL url = null; 
    Log.d(LOGTAG, " " + "location " + location); 
    try { 
     url = new URL(location); 
    } catch (MalformedURLException e) { 
     Log.e(LOGTAG, " " + "error" + e.getMessage()); 
    } 
    if (url != null) { 
     try { 
      HttpURLConnection connection = (HttpURLConnection) url 
        .openConnection(); 
      BufferedReader in = new BufferedReader(new InputStreamReader(
        connection.getInputStream())); 
      String inputLine; 
      int lineCount = 0; 
      while ((inputLine = in.readLine()) != null) { 
       result += inputLine.trim(); 
      } 

      in.close(); 
      connection.disconnect(); 
     } catch (Exception e) { 

      Log.e(LOGTAG, " " + "IOError " + e.getMessage()); 
      Toast.makeText(getBaseContext(), "No Internet Access", 
        Toast.LENGTH_SHORT); 
     } 
    } else { 
     Log.e(LOGTAG, " " + "url" + url); 
    } 
    return result; 
} 

class PostToTwitter extends AsyncTask<String, Void, String> { 

    @Override 
    protected String doInBackground(String... params) { 

     Login(); 
     Log.d(LOGTAG, "Success"); 
     Log.d(LOGTAG, result); 
     Log.d(LOGTAG, result.substring(0, 16).trim()); 
     // Log.d(TweetActivity.getLogtag(),"Successfully Posted: " + 
     // params[0]); 

     return "success"; 
    } 

    @Override 
    protected void onPostExecute(String r) { 
     // TODO Auto-generated method stub 
     super.onPostExecute(result); 
     String msg = "Login successful"; 

     if (result.substring(0, 16).trim().equals(msg)) { 
      // System.out.println(result.substring(0, 16).trim()); 
      Log.d(LOGTAG, " " + "Connection Test" + result); 
      AlertDialog.Builder builder = new AlertDialog.Builder(getApplicationContext()); 
      builder.setMessage("Are you sure send this SMS?") 
        .setCancelable(false) 
        .setPositiveButton("Yes", new DialogInterface.OnClickListener() { 
         public void onClick(DialogInterface dialog, int id) { 
          //...Attach another thread event to send the sms 
         } 
        }) 
        .setNegativeButton("No", new DialogInterface.OnClickListener() { 
         public void onClick(DialogInterface dialog, int id) { 
          dialog.cancel(); 
         } 
        }); 
      Log.e(LOGTAG, "Error detected 2"); 
      AlertDialog alert = builder.create(); 
      alert.show(); 
      //return "success"; 
      // Toast.makeText(getBaseContext(), 
      // "Login Succesful",Toast.LENGTH_SHORT).show(); 

     } else { 
      Toast.makeText(getBaseContext(), 
        "Login UnSuccesful. Check Username or password", 
        Toast.LENGTH_SHORT).show(); 
      //return null; 
     } 
     // Toast.makeText(getApplicationContext(), result 
     // ,Toast.LENGTH_SHORT).show(); 
     Log.e(LOGTAG, "Error detected"); 

     /* 
     Intent i = new Intent("com.sms.subsahara.COMPOSESMS"); 
     startActivity(i); 
     //Log.e(LOGTAG, " " + "error2");*/ 

    } 

} 

在亞歷克斯應用的建議,我修改了上面這個原代碼,但仍得到一個錯誤。下面是從logcat的

E/AndroidRuntime( 326): Uncaught handler: thread main exiting due to uncaught exception 
E/AndroidRuntime( 326): android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application 
E/AndroidRuntime( 326):  at android.view.ViewRoot.setView(ViewRoot.java:472) 
E/AndroidRuntime( 326):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177) 
E/AndroidRuntime( 326):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91) 
E/AndroidRuntime( 326):  at android.app.Dialog.show(Dialog.java:239) 
E/AndroidRuntime( 326):  at com.sms.subsahara.WebMessengerActivity$PostToTwitter.onPostExecute(WebMessengerActivity.java:216) 
E/AndroidRuntime( 326):  at com.sms.subsahara.WebMessengerActivity$PostToTwitter.onPostExecute(WebMessengerActivity.java:1) 
E/AndroidRuntime( 326):  at android.os.AsyncTask.finish(AsyncTask.java:417) 
E/AndroidRuntime( 326):  at android.os.AsyncTask.access$300(AsyncTask.java:127) 
E/AndroidRuntime( 326):  at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429) 
E/AndroidRuntime( 326):  at android.os.Handler.dispatchMessage(Handler.java:99) 
E/AndroidRuntime( 326):  at android.os.Looper.loop(Looper.java:123) 
E/AndroidRuntime( 326):  at android.app.ActivityThread.main(ActivityThread.java:4363) 
E/AndroidRuntime( 326):  at java.lang.reflect.Method.invokeNative(Native Method) 
E/AndroidRuntime( 326):  at java.lang.reflect.Method.invoke(Method.java:521) 
E/AndroidRuntime( 326):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860) 
E/AndroidRuntime( 326):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 
E/AndroidRuntime( 326):  at dalvik.system.NativeStart.main(Native Method) 

回答

8

doInBackground不與UI線程同步,這意味着您不能直接操作UI元素,從該方法中啓動對話框等。修復很簡單。只需將您的AlertDialog代碼移動到onPostExecute方法(其中與UI線程同步)。

AsyncTask s工作,請記住:

  1. doInBackground是爲了進行潛在的昂貴的操作(網絡訪問,套接字連接,數據庫查詢等)
  2. onPostExecute是爲了做一些事情結果,如果你願意(這種方法與UI線程同步,所以你可以直接操縱UI元素)
+0

這個人是現貨。只執行必須獨立於後臺UI線程完成的進程。 –

+0

@ jack57,爲什麼謝謝你,善良的先生! –

+1

但我認爲你的意思是「操作」,而不是「過程」。好吧,我知道你是什麼意思......但僅僅是爲了技術...:P –

1

我想這是因爲你登錄()是的AsyncTask執行的內部,而不是在裏面mainUI執行除外。可以將onPostExecute處理程序放在裏面,回到主線程執行;也可以用onPostExecute UIThread:

runOnUiThread(new Runnable() { 
       @Override 
        public void run() { 
        Login();  
        } 
       }); 

我希望它能幫助你。

+0

這個答案的第一句是正確的......但答案的其餘部分是完全錯誤的。 (1)'onPostExecute'在UI線程上運行,因此創建一個'Runnable'並使用'runOnUiThread'執行代碼只會讓你放慢速度,(2)你是否確實要執行* Login *代碼在'onPostExecute' ??這不符合使用'AsyncTask'的全部目的嗎?! –

3

DoInBackground()只能在不同的t比主UI線程更重要。這是AsyncTask的重點。

有3種方式來發表您的結果到UI(幾乎......到UI線程)

  1. 使用onPostExecute方法。你得到你傳入的doInBackground方法的返回值,你可以用它做任何事情。 (我認爲這與您的使用案例相符)。

  2. 如果您的任務正在進行,並且您希望在UI上發出少量突發信息(如進度條更新),請使用doInBackground方法中的publishProgress(...)然後將其傳遞給AsyncTask中的onProgressUpdate(...)方法,該方法將在UI線程上運行。

  3. 與2相似,但可以使用RunOnUiThread(...)方便的方法來拋出一個runnable在UI線程中運行。當你有多個匿名方法時,可能不會是最漂亮的代碼,但它是快速和骯髒的方式來做到這一點。請注意,此方法可用於Activity類,而不是Context類,對於某些情況可能是交易斷路器。

+0

,因爲Context的大多數子類甚至沒有UI,所以實現'runOnUiMethod'沒有什麼意義。 –

0

@Alex洛克伍德

AsyncTask.doInBackground(Void..params)不適合很長時間和重複操作,更好的替代將是一個HandlerThread

原因:

在Android 3.2的,的AsyncTask在顯著的方式改變了它的實現。從Android 3.2開始,AsyncTask 不會爲AsyncTask中的每個實例創建線程,而是使用執行程序爲單個後臺線程上的所有AsyncTasks運行後臺工作。這意味着每個AsyncTask線程必須一個接一個地運行。所以,舉例來說,如果你有一個很長的AsyncTask線程(來自REST的圖像獲取器),我建議使用HandlerThread代替,因爲運行線程的長任務可能會延遲整個鏈。

有可能並行使用線程池執行,而不是安全運行的AsyncTask,但我不知道確切的原因,程序員不推薦這樣做的背後有幾個原因與本文無關。但是如果你這樣做,我會建議你做自己的線程,使用處理程序在必要時與主線程通信。