1

I am trying to call a PHP script over my server using the code shown below. This code is giving me very strange results. Occasionally it will desplay the result desired from the PHP command but 9/10 it just displays a blank screen.

I am getting this in Logcat:

Only the original thread that created a view hierarchy can touch it's views?

How can I change my code to always display results?

note: I have seen this answer but I am not sure how to relate it to my specific code.

Android activity code:

public class SimpleServer extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {


        super.onCreate(savedInstanceState);
        setContentView(R.layout.simpleserver);

        final TextView testView= (TextView)findViewById(R.id.tvSimpleServer);



        Thread thread = new Thread(new Runnable(){
            @Override
            public void run() {
                try {
                    Log.d("start", "start");

                    String link = "http://www.cs.qub.ac.uk/40006697/server2.php?command=getAnimalSound&animal=bird";



                    try {
                        URL url = new URL(link);
                    } catch (MalformedURLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    HttpClient client = new DefaultHttpClient();


                    HttpGet request = new HttpGet();
                    try {

                        request.setURI(new URI(link));

                    } catch (URISyntaxException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    Log.d("abouttorequest", "about to req");
                    HttpResponse response = null;

                    try {
                        response = client.execute(request);
                        Log.d("afterrequest", "after req");
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();

                    }
                    try {
                        BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

                        //String test= in.toString();



                         String line;
                            while ((line = in.readLine()) != null) {

                                testView.setText("Response:  " + line);
                            }

                        Log.d("testingscript", "hello");
                    } catch (IllegalStateException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }



                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        thread.start(); 





    }


}

Logcat report (note that about to req, after req etc are trace code Logs):

08-07 20:07:02.646: D/AbsListView(10298): onVisibilityChanged() is called, visibility : 0
08-07 20:07:02.646: D/AbsListView(10298): unregisterIRListener() is called 
08-07 20:07:02.666: D/AbsListView(10298): unregisterIRListener() is called 
08-07 20:07:03.487: D/AbsListView(10298): unregisterIRListener() is called 
08-07 20:07:03.487: W/ApplicationPackageManager(10298): getCSCPackageItemText()
08-07 20:07:03.517: D/start(10298): start
08-07 20:07:03.517: D/abouttorequest(10298): about to req
08-07 20:07:03.637: D/afterrequest(10298): after req
08-07 20:07:03.637: W/System.err(10298): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
08-07 20:07:03.637: W/System.err(10298):    at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6909)
08-07 20:07:03.637: W/System.err(10298):    at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1054)
08-07 20:07:03.637: W/System.err(10298):    at android.view.View.requestLayout(View.java:17321)
08-07 20:07:03.637: W/System.err(10298):    at android.view.View.requestLayout(View.java:17321)
08-07 20:07:03.647: W/System.err(10298):    at android.view.View.requestLayout(View.java:17321)
08-07 20:07:03.647: W/System.err(10298):    at android.view.View.requestLayout(View.java:17321)
08-07 20:07:03.647: W/System.err(10298):    at android.view.View.requestLayout(View.java:17321)
08-07 20:07:03.647: W/System.err(10298):    at android.widget.TextView.checkForRelayout(TextView.java:8003)
08-07 20:07:03.647: W/System.err(10298):    at android.widget.TextView.setText(TextView.java:4840)
08-07 20:07:03.647: W/System.err(10298):    at android.widget.TextView.setText(TextView.java:4672)
08-07 20:07:03.647: W/System.err(10298):    at android.widget.TextView.setText(TextView.java:4647)
08-07 20:07:03.647: W/System.err(10298):    at com.example.brianapp.SimpleServer$1.run(SimpleServer.java:103)
08-07 20:07:03.647: W/System.err(10298):    at java.lang.Thread.run(Thread.java:841)
08-07 20:07:03.938: D/AbsListView(10298): onVisibilityChanged() is called, visibility : 4
08-07 20:07:03.938: D/AbsListView(10298): unregisterIRListener() is called 
Community
  • 1
  • 1
codeme2020
  • 853
  • 2
  • 13
  • 20

3 Answers3

0
testView.setText("Response:  " + line);

You cannot do that because you're running a new thread and this cant interact with the 'main' or the GUI thread. I suggest you use async tasks.

//our async task for sending web requests
    private class SendHttpRequest extends AsyncTask<Objct, Void, String> {
        String responseBack = "";

        @Override
        protected String doInBackground(Object... args) {

            try {
                Log.d("start", "start");

                String link = "http://www.cs.qub.ac.uk/40006697/server2.php?command=getAnimalSound&animal=bird";



                try {
                    URL url = new URL(link);
                } catch (MalformedURLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                HttpClient client = new DefaultHttpClient();


                HttpGet request = new HttpGet();
                try {

                    request.setURI(new URI(link));

                } catch (URISyntaxException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                Log.d("abouttorequest", "about to req");
                HttpResponse response = null;

                try {
                    response = client.execute(request);
                    Log.d("afterrequest", "after req");
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();

                }
                try {
                    BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

                    //String test= in.toString();



                     String line;
                        while ((line = in.readLine()) != null) {

                            //testView.setText("Response:  " + line);//replace with
                            responseBack = line;
                        }

                    Log.d("testingscript", "hello");
                } catch (IllegalStateException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }



            } catch (Exception e) {
                e.printStackTrace();
            }
          return responseBack;
        }

        @Override
        protected void onPostExecute(String result) {
           testView.setText("Response:  " + result);
        }
    }

Then you can call it anywhere like this.

new SendHttpRequest().execute();
someguy234
  • 559
  • 4
  • 17
0

You cant edit any UI components from thread other than UI thread ( the one which created UI stuff ) wrap your code like

        final String data = line;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                testView.setText("Response:  " + data);
            }
        });

or

    final String data = line;
    testView.post(new Runnable() {
        @Override
        public void run() {
            testView.setText("Response:  " + data);
        }
    });
nizammoidu
  • 2,074
  • 1
  • 14
  • 14
0

There are 2 ways to handle this kind of thing. First is to do your networking in an AsyncTask, then pass the result of the call back to your main method using the built in onPostExecute method.

The other is to create a thread inside your already existing thread. Since you are trying to set the text in your testView object, you can do the following:

testView.post(new Runnable() {
    public void run() {
        testView.setText("Response:  " + line);
    }
});

Again, place this inside your Thread and you should be fine.

Brett Haines
  • 184
  • 3
  • 14
  • Thank you this seems like a simple solution, how do I actually add this code to my current code though? sorry I am very new – codeme2020 Aug 07 '14 at 19:29
  • I would just try replacing `testView.setText("Response: " + line);` with the code in my answer. Although I should mention that the AsyncTask is the more proper and officially-recomended way to do network calls. – Brett Haines Aug 07 '14 at 19:34