2013年12月19日 星期四

android.os.NetworkOnMainThreadException的問題

自從將 Android 升級成 4.2 之後,httpRequest 就出現了 android.os.NetworkOnMainThreadException 這個問題

在網路上查過之後才發現原來 Android 為了怕開發者將 HTTP 傳送請求放在主程式中,如果 HTTP 這個要求一直持續的話很有可能會卡死整個程式,造成應用程式的 crash 因此 Android 非常貼心的幫助開發者判斷 httpRequest 這個方法是否是在主程式中運行,如果是的話便會拋出錯誤

而如果想要解決這問題就是要將 httpRequest 寫在多執行緒中,以下是其中一種解法

public class MainActivity extends Activity{
 
 private EditText txtMessage;
    private Button sendBtn;
    private String uriAPI = "你要傳送要求的網址";
    String msg = null;
    @Override

    public void onCreate(Bundle savedInstanceState){

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        txtMessage = (EditText) findViewById(R.id.txt_message);
        sendBtn = (Button) findViewById(R.id.send_btn);
        sendBtn.setOnClickListener(sendlistener);
        
    }
    private Runnable mutiThread = new Runnable(){
      public void run(){
      // 運行網路連線的程式
      msg = txtMessage.getEditableText().toString();
      String r = sendPostDataToInternet(msg);
      if (r != null)
      Log.d("first0.0", r);

    }
  };
  public OnClickListener sendlistener = new OnClickListener(){
    public void onClick(View v){
      if (v == sendBtn){
        if (txtMessage != null){
              /* 
               * 這邊要用 Thread 是因為 Android 改版之後
               * 會對在主程式裡跑網路連接的程式碼做 Exception 的意外排除動作
               * 因此要把網路連線使用多執行緒的方式去運行,才不會被當成例外錯誤拋出
               */
               Thread thread = new Thread(mutiThread);
               thread.start();
         }
       }
     }
   };
    
    
    private String sendPostDataToInternet(String strTxt){

        /* HTTP Post */
        HttpPost httpRequest = new HttpPost(uriAPI);

        /* 將 Post 值存為一個 NameValuePair[],在這邊去添加自己想要的值 */
        List params = new ArrayList();

        params.add(new BasicNameValuePair("APIMethod", "phoneTest"));
        /* 這邊 PHP 端的接法就是用 $_POST['data']就接的到這邊的 strTxt 這個變數值了 */
        try{
         
            /* 設定 HTTP request */
            httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));

            /* 傳送 HTTP response */
            HttpResponse httpResponse = new DefaultHttpClient().execute(httpRequest);
            
            /* 如果回傳值為 200 即為傳送 ok */
            if (httpResponse.getStatusLine().getStatusCode() == 200){

             /* 接收回傳字串,這邊接的值就是在 PHP 那邊 echo 的值 */ 
             /* hellow.php 這隻程式碼的寫法:
              * if($_POST['data']!=null) echo $_POST['data']; */
              
                String strResult = EntityUtils.toString(httpResponse.getEntity());
            
                return strResult;
            }
            else{
                Log.d("sss", "no message");
            }
        } catch (ClientProtocolException e){
         Log.d("@@", e.toString());
        } catch (IOException e){
         Log.d("@@", e.toString());
        } catch (Exception e){
         Log.d("@@", e.toString());
        }
        return null;
    }
}