Ошибка «Только оригинальный поток, создавший иерархию представлений, может коснуться его представлений» в Android

Я создаю простое приложение для входа в систему с помощью Android и PHP, но я получаю сообщение об ошибке, может ли кто-нибудь мне помочь? Я пытаюсь установить связь между Android как клиентской стороной и PHP / MySQL как серверной, но все равно не получил ответ успешно.

AndroidLogin.java

package com.sencide; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; import android.os.Bundle; import android.os.StrictMode; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class AndroidLogin extends Activity implements OnClickListener { Button ok,back,exit; TextView result; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); // Login button clicked ok = (Button)findViewById(R.id.btn_login); ok.setOnClickListener(this); result = (TextView)findViewById(R.id.lbl_result); } public void postLoginData() { // Create a new HttpClient and Post Header HttpClient httpclient = new DefaultHttpClient(); Log.e("Responce-->","after httpclient"); /* login.php returns true if username and password is equal to saranga */ HttpPost httppost = new HttpPost("http://10.0.2.2/login.php"); Log.e("Responce-->","after httppost"); try { // Add user name and password EditText uname = (EditText)findViewById(R.id.txt_username); String username = uname.getText().toString(); EditText pword = (EditText)findViewById(R.id.txt_password); String password = pword.getText().toString(); List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); nameValuePairs.add(new BasicNameValuePair("username", username)); nameValuePairs.add(new BasicNameValuePair("password", password)); httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); Log.e("Responce-->","after using the list name pair"); // Execute HTTP Post Request Log.w("SENCIDE", "Execute HTTP Post Request"); HttpResponse response = httpclient.execute(httppost); Log.e("Responce-->","after execute the http response"); // String str = inputStreamToString(response.getEntity().getContent()).toString(); String str = EntityUtils.toString(response.getEntity(), HTTP.UTF_8); //Log.w("SENCIDE", str); Log.e("Responce-->",""+str); if(str.toString().equalsIgnoreCase("true")) { Log.w("SENCIDE", "TRUE"); result.setText("Login successful"); }else { Log.w("SENCIDE", "FALSE"); result.setText(str); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private StringBuilder inputStreamToString(InputStream is) { String line = ""; StringBuilder total = new StringBuilder(); // Wrap a BufferedReader around the InputStream BufferedReader rd = new BufferedReader(new InputStreamReader(is)); // Read response until the end try { while ((line = rd.readLine()) != null) { total.append(line); } } catch (IOException e) { e.printStackTrace(); } // Return full string return total; } /* login.php returns true if username and password is equal to test1 */ @Override public void onClick(View view) { // TODO Auto-generated method stub final String resultText; if(str.toString().equalsIgnoreCase("true")) { resultText = "Login successful"; }else { resultText = str; } if(view == ok){ Thread t = new Thread(){ public void run(){ postLoginData(); result.post(new Runnable() { public void run() { result.setText(resultText); } }); } }; t.start(); } } } 

log cat

  04-04 19:04:20.504: E/Responce-->(457): after httpclient 04-04 19:04:20.517: E/Responce-->(457): after httppost 04-04 19:04:20.544: E/Responce-->(457): after using the list name pair 04-04 19:04:20.544: W/SENCIDE(457): Execute HTTP Post Request 04-04 19:04:20.824: E/Responce-->(457): after execute the http response 04-04 19:04:20.834: E/Responce-->(457): true 04-04 19:04:20.834: W/SENCIDE(457): TRUE 04-04 19:04:20.844: W/dalvikvm(457): threadid=9: thread exiting with uncaught exception (group=0x40015560) 04-04 19:04:20.912: E/AndroidRuntime(457): FATAL EXCEPTION: Thread-10 04-04 19:04:20.912: E/AndroidRuntime(457): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 04-04 19:04:20.912: E/AndroidRuntime(457): at android.view.ViewRoot.checkThread(ViewRoot.java:2932) 04-04 19:04:20.912: E/AndroidRuntime(457): at android.view.ViewRoot.requestLayout(ViewRoot.java:629) 04-04 19:04:20.912: E/AndroidRuntime(457): at android.view.View.requestLayout(View.java:8267) 04-04 19:04:20.912: E/AndroidRuntime(457): at android.view.View.requestLayout(View.java:8267) 04-04 19:04:20.912: E/AndroidRuntime(457): at android.view.View.requestLayout(View.java:8267) 04-04 19:04:20.912: E/AndroidRuntime(457): at android.view.View.requestLayout(View.java:8267) 04-04 19:04:20.912: E/AndroidRuntime(457): at android.view.View.requestLayout(View.java:8267) 04-04 19:04:20.912: E/AndroidRuntime(457): at android.widget.TextView.checkForRelayout(TextView.java:5521) 04-04 19:04:20.912: E/AndroidRuntime(457): at android.widget.TextView.setText(TextView.java:2724) 04-04 19:04:20.912: E/AndroidRuntime(457): at android.widget.TextView.setText(TextView.java:2592) 04-04 19:04:20.912: E/AndroidRuntime(457): at android.widget.TextView.setText(TextView.java:2567) 04-04 19:04:20.912: E/AndroidRuntime(457): at com.sencide.AndroidLogin$1.run(AndroidLogin.java:136) 04-04 19:04:23.464: I/Process(457): Sending signal. PID: 457 SIG: 9 

PHP-код

 <?php $host="localhost"; // Host name $username="root"; // Mysql username $password="root"; // Mysql password $db_name="testlogin"; // Database name $tbl_name="members"; // Table name // Connect to server and select databse. mysql_connect("$host", "$username", "$password")or die("cannot connect"); mysql_select_db("$db_name")or die("cannot select DB"); // username and password sent from form $myusername=$_POST['username']; $mypassword=$_POST['password']; // To protect MySQL injection $myusername = stripslashes($myusername); $mypassword = stripslashes($mypassword); $myusername = mysql_real_escape_string($myusername); $mypassword = mysql_real_escape_string($mypassword); $sql="SELECT * FROM $tbl_name WHERE username='$myusername' and password='$mypassword'"; $result=mysql_query($sql); // Mysql_num_row is counting table row $count=mysql_num_rows($result); // If result matched $myusername and $mypassword, table row must be 1 row if($count==1){ echo "true"; } else { echo "Login Failed"; } ?> 

ОК. Я внес некоторые изменения в ваш код, он по-прежнему уродлив и требует много рефакторинга, но скажите мне, выбрасывает ли он какие-либо исключения.

EDIT: добавлено ваше username и password передаваемые запросу, в качестве параметров вашего postLoginData(String password,String username) . Это должно сделать это.


 import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; import android.os.Bundle; import android.os.StrictMode; import android.app.Activity; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class AndroidLogin extends Activity implements OnClickListener { Button ok, back, exit; TextView result; EditText uname; EditText pword; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); // Login button clicked ok = (Button) findViewById(R.id.btn_login); ok.setOnClickListener(this); uname = (EditText) findViewById(R.id.txt_username); pword = (EditText) findViewById(R.id.txt_password); result = (TextView) findViewById(R.id.lbl_result); } @Override public void onClick(View view) { // TODO Auto-generated method stub final String resultText; final String username = uname.getText().toString(); final String password = pword.getText().toString(); if (view == ok) { Thread t = new Thread() { public void run() { postLoginData(username,password); } }; t.start(); } } private void postLoginData(String username,String password) { try { // Create a new HttpClient and Post Header HttpClient httpclient = new DefaultHttpClient(); Log.e("Response-->", "after httpclient"); /* login.php returns true if username and password is equal to saranga */ HttpPost httppost = new HttpPost("http://10.0.2.2/login.php"); Log.e("Response-->", "after httppost"); List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); nameValuePairs.add(new BasicNameValuePair("username", username)); nameValuePairs.add(new BasicNameValuePair("password", password)); httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); Log.e("Responce-->", "after using the list name pair"); // Execute HTTP Post Request Log.w("SENCIDE", "Execute HTTP Post Request"); HttpResponse response = httpclient.execute(httppost); Log.e("Responce-->", "after execute the http response"); String str = EntityUtils.toString(response.getEntity(), HTTP.UTF_8); if (str.toString().equalsIgnoreCase("true")) { runOnUiThread(new Runnable() { public void run() { result.setText("Login Successful"); } }); } else { runOnUiThread(new Runnable() { public void run() { result.setText("Duh"); } }); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } 

Решение находится в журнале из logcat:

 04-04 18:38:47.596: E/AndroidRuntime(413): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 

Проводка пользователя / пароля работает. Вы получите «истинный» ответ в порядке, но затем вы пытаетесь установить ярлык или подобное, в представлении, созданном вне потока. Это не-нет.

 result.setText("Login successful"); 

Посмотрите документы Android SDK о потоках / процессах о том, как обновлять представления из других потоков: http://developer.android.com/guide/components/processes-and-threads.html

Вы не можете вносить изменения в андроидные виды из основного потока пользовательского интерфейса. В вашем примере вы начинаете новый поток и запускаете postLoginData (). Поскольку postLoginData ALSO устанавливает текст текстового представления, вы получаете эту ошибку.

Вы должны: выполнить запрос http в своем новом потоке, а затем в потоке пользовательского интерфейса изменить текст.

Существует множество способов сделать это.

  • AsyncTask
  • укротитель

И этот супер простой, но, вероятно, не рекомендуемый способ сделать это, чтобы просто поднять вас на ноги. Yo захочет сделать это в любое время, когда вы вносите изменения в свой новый поток в пользовательский интерфейс, поэтому в этом примере, когда вы устанавливаете текст результата.

 result.post(new Runnable() { public void run() { result.setText(str); } }); } 

Что будет работать в потоке пользовательского интерфейса. Вы действительно должны посмотреть на два варианта, которые я разместил первым, или вы просто столкнетесь с большими проблемами.

** edit ** Вам нужно просто заменить этот код для публикации в основном потоке, а не в новом потоке.

 if(str.toString().equalsIgnoreCase("true")) { Log.w("SENCIDE", "TRUE"); result.setText("Login successful"); }else { Log.w("SENCIDE", "FALSE"); result.setText(str); } 

Сделайте это так:

 final String resultText; if(str.toString().equalsIgnoreCase("true")) { resultText = "Login successful"; }else { resultText = str; } result.post(new Runnable() { public void run() { result.setText(resultText); } }); }