【问题标题】:Android app freezes/crashed when sending data in a new thread on button click在单击按钮时在新线程中发送数据时,Android 应用程序冻结/崩溃
【发布时间】:2014-05-28 13:44:07
【问题描述】:

因此,在单击按钮时,我创建了一个新线程,然后将数据发送到 asp.net 脚本,发送数据后,我正在“清除”EditText 字段。但是,在我发送数据后,textview 没有被清除,应用程序冻结并且有时崩溃。这是我的活动代码:

http://www.mstreetllc.com/Lab.asp

package com.example.testphp;

import java.io.IOException;

import org.apache.http.client.ClientProtocolException;

import java.util.ArrayList;
import java.util.List;

import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.message.BasicNameValuePair;


// import everything you need
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {

Button sendButton;

EditText msgTextField;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // load the layout
    setContentView(R.layout.fragment_main);

    // make message text field object
    msgTextField = (EditText) findViewById(R.id.msgTextField);
    // make send button object
    sendButton = (Button) findViewById(R.id.sendButton);

    sendButton.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            Thread thread = new Thread(new Runnable(){
                @Override
                public void run() {
                    try {
                        // get the message from the message text box
                        String msg = msgTextField.getText().toString();

                        // make sure the fields are not empty
                        if (msg.length() > 0) {
                            HttpClient httpclient = new DefaultHttpClient();
                            HttpPost httppost = new HttpPost("http://www.mstreetllc.com/Lab.asp");
                            try {
                                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(
                                        2);
                                nameValuePairs.add(new BasicNameValuePair("id", "12345"));
                                nameValuePairs.add(new BasicNameValuePair("message", msg));
                                httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                                httpclient.execute(httppost);
                                msgTextField.setText(""); // clear text box
                            } catch (ClientProtocolException e) {
                                // TODO Auto-generated catch block
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                            }

                        } else {
                            // display message if text fields are empty
                            Toast.makeText(getBaseContext(), "All field are required",
                                    Toast.LENGTH_SHORT).show();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });

            thread.start(); 
        }
    });

}


}

我不确定是线程还是发送数据导致它冻结。有什么想法吗?

Logcat:

05-28 09:45:32.325: W/System.err(32478): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
05-28 09:45:32.341: W/System.err(32478):    at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:5908)
05-28 09:45:32.341: W/System.err(32478):    at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:869)
05-28 09:45:32.341: W/System.err(32478):    at android.view.ViewGroup.invalidateChild(ViewGroup.java:4253)
05-28 09:45:32.341: W/System.err(32478):    at android.view.View.invalidate(View.java:10489)
05-28 09:45:32.341: W/System.err(32478):    at android.widget.TextView.invalidateRegion(TextView.java:4591)
05-28 09:45:32.341: W/System.err(32478):    at android.widget.TextView.invalidateCursor(TextView.java:4534)
05-28 09:45:32.341: W/System.err(32478):    at android.widget.TextView.spanChange(TextView.java:7412)
05-28 09:45:32.341: W/System.err(32478):    at android.widget.TextView$ChangeWatcher.onSpanAdded(TextView.java:9103)
05-28 09:45:32.341: W/System.err(32478):    at android.text.SpannableStringBuilder.sendSpanAdded(SpannableStringBuilder.java:979)
05-28 09:45:32.341: W/System.err(32478):    at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:688)
05-28 09:45:32.341: W/System.err(32478):    at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:588)
05-28 09:45:32.349: W/System.err(32478):    at android.text.Selection.setSelection(Selection.java:76)
05-28 09:45:32.349: W/System.err(32478):    at android.text.Selection.setSelection(Selection.java:87)
05-28 09:45:32.349: W/System.err(32478):    at android.text.method.ArrowKeyMovementMethod.initialize(ArrowKeyMovementMethod.java:302)
05-28 09:45:32.349: W/System.err(32478):    at android.widget.TextView.setText(TextView.java:3759)
05-28 09:45:32.349: W/System.err(32478):    at android.widget.TextView.setText(TextView.java:3629)
05-28 09:45:32.349: W/System.err(32478):    at android.widget.EditText.setText(EditText.java:80)
05-28 09:45:32.349: W/System.err(32478):    at android.widget.TextView.setText(TextView.java:3604)
05-28 09:45:32.349: W/System.err(32478):    at com.example.testphp.MainActivity$1$1.run(MainActivity.java:68)
05-28 09:45:32.349: W/System.err(32478):    at java.lang.Thread.run(Thread.java:841)

【问题讨论】:

  • 你有这个问题的日志吗?

标签: java android asp.net multithreading


【解决方案1】:

只有 UI 线程可以对 UI 进行更改。对线程中视图的任何更改都需要在 runOnUIThread 块中完成或通过处理程序发送到 UI 线程。

【讨论】:

    【解决方案2】:

    你的代码的问题是

    msgTextField.setText("");
    

    如错误消息中所述,您无法从替代线程访问您的视图层次结构。只有主 UI 线程可以访问它。

    您可能想查看AsyncTask 类,这正是您访问远程服务器所需要的。然后,您将在 doInBackground() 方法上执行代码,然后修改视图 onPostExecute()。

    【讨论】:

      【解决方案3】:

      问题是,您正在尝试从非 UI 线程更新 UI 线程。

      您可以尝试如下(未测试):

      public void onClick(View v) {
        new Thread(new Runnable() {
          public void run() {
            msgTextField.post(new Runnable() {  //<-- This instead of your setText();
              public void run() {
                mImageView.setText("");
              }
            });
          }
        }).start();
      }
      

      参考资料:

      Android Developers

      Developers.Android.com

      Update UI from Thread

      How to set text of text view in another thread

      【讨论】:

        【解决方案4】:

        您应该创建一个AsyncTask 并在那里处理HttpPost

        public  class  Post extends AsyncTask<String, Void, Void> {
        
            private  Activity   callingActivity   =   null;
        
            public Post(Activity  paramActivity) {
                callingActivity    =    paramActivity;
            }
        
            protected Void doInBackground(String... msg) {
                if (msg[0].length() > 0) {
                    HttpClient httpclient = new DefaultHttpClient();
                    HttpPost httppost = new HttpPost("http://www.mstreetllc.com/Lab.asp");
                    try {
                        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
                        nameValuePairs.add(new BasicNameValuePair("id", "12345"));
                        nameValuePairs.add(new BasicNameValuePair("message", msg[0]));
                        httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                        httpclient.execute(httppost);
                    } 
                    catch (ClientProtocolException e) {
                        // TODO Auto-generated catch block
                    } 
                    catch (IOException e) {
                        // TODO Auto-generated catch block
                    }
                }
            }
        
            protected void onPostExecute(Void result) {
                EditText  msgTextField  =  (EditText) callingActivity.findViewById(R.id.msgTextField); 
                msgTextField.setText("");      
            }
        }
        

        要调用这个AsyncTask,只需写:

        new Post(this).execute(msg);
        

        更多关于AsyncTaskshttp://developer.android.com/reference/android/os/AsyncTask.html

        【讨论】:

          【解决方案5】:

          我认为是 HTTP 请求中的问题。

          为网络请求使用另一个库,例如 VolleyhttpSync

          【讨论】:

            猜你喜欢
            • 2017-03-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多