0

I am writing an android application, I previously had a problem NetworkOnMainThreadException and I solved using threads. I now don't get any error and also I don't get any output.

here is my code: there is no errors in the LogCat

public class Currency_convert extends Activity {
    public int to;
    public int from;
    public String [] val;
    public String s;
    public Handler handler;
    public double am=0.0;
    StringBuilder build=null ;

    HttpClient client=null;
    HttpGet httpGet =null;
    HttpResponse response=null;
    HttpEntity entity=null;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.currency);
        Spinner s1 = (Spinner) findViewById(R.id.spinner11);
        Spinner s2 = (Spinner) findViewById(R.id.spinner22);
        final EditText e=(EditText) findViewById(R.id.amountt);
       // am=Double.parseDouble(e.getText().toString());
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
                this, R.array.name, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.select_dialog_singlechoice);
        val  = getResources().getStringArray(R.array.value);
        s1.setAdapter(adapter);
        s2.setAdapter(adapter);
        s1.setOnItemSelectedListener(new spinOne(1));
        s2.setOnItemSelectedListener(new spinOne(2));
        Button b = (Button) findViewById(R.id.button11);
        b.setOnClickListener(new OnClickListener(){

            public void onClick(View v) {
                TextView t = (TextView) findViewById(R.id.textView44);  
                if(from == to) {
                    Toast.makeText(getApplicationContext(), "Invalid", 4000).show();
                }
                else {                                      
                      try {
                         s = getJson("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22"+val[from]+val[to]+"%22)&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=");                       
                    //s=getJson("http://www.google.com/ig/calculator?hl=en&q=1USD=?INR");
                         JSONObject jObj;
                        jObj = new JSONObject(s);
                        String exResult = jObj.getJSONObject("query").getJSONObject("results").getJSONObject("rate").getString("Rate");
                          am=Double.parseDouble(e.getText().toString());
                        double totalR=(Double.parseDouble(exResult))*am;
                        String r=String.valueOf(totalR);
                        t.setText(r);
                    //  Log.println(priority, tag, msg)
                        System.out.println("r =" +r);
                        Log.i("hello", r);
                        } catch (JSONException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        catch (ClientProtocolException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }                                                    
                    }                                           
                }                               
        });
    }

    public String getJson(final String url)throws ClientProtocolException, IOException  {
   // private  String getJson(String url)throws ClientProtocolException, IOException e {
        build = new StringBuilder();

        client = new DefaultHttpClient();
        httpGet = new HttpGet(url);

         new Thread(new Runnable() {
            public void run() {

                    try {
                        response = client.execute(httpGet);
                        entity = response.getEntity();
                        InputStream content = entity.getContent();
                        BufferedReader reader = new BufferedReader(new InputStreamReader(content));
                        String con;
                        while ((con = reader.readLine()) != null) {
                            build.append(con);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
        }
        }).start();     
    //    response = client.execute(httpGet);
    //   entity = response.getEntity();
    //  InputStream content = entity.getContent();
    //  BufferedReader reader = new BufferedReader(new InputStreamReader(content));
    //  String con;
    //  while ((con = reader.readLine()) != null) {
        //          build.append(con);
            //  }
    return build.toString();
        //return url;
}
    private class SpinOne implements OnItemSelectedListener {
        int ide;
        SpinOne(int i) {
            ide =i;
        }
        public void onItemSelected(AdapterView<?> parent, View view,
                int index, long id) {
            if(ide == 1) {
                from = index;
                    }
            else if(ide == 2) {
                to = index;
                    }

        }

        public void onNothingSelected(AdapterView<?> arg0) {
            // TODO Auto-generated method stub  
        }           
    }}
Jayasagar
  • 2,046
  • 19
  • 22
ruaa.brkat
  • 41
  • 1
  • 8
  • Have you debugged to see what code is/isn't getting called? – codeMagic Nov 07 '13 at 18:02
  • change all `e.printStackTrace();` to `Log.e("LOGTAG", e.getMessage(), e);` and check logcat – petey Nov 07 '13 at 18:03
  • The problem here is Your thread has been started by Android UI main thread, so after this main UI thread and your thread both runs parallel, I am sure UI Main thread should already executed 'return build.toString();', you get back with empty result, Where your thread doing job but might be late already. – Jayasagar Nov 07 '13 at 18:05

3 Answers3

3

The way it is written, getJson() will return immediately without giving time for the thread to run completely, so the returned value will not be what you want. Use an AsyncTask so you can run your thread code in the AsyncTask's doInBackground() method and then pass the result to the onPostExecute() method where you can then perform setText() as you intend.

An alternative is to move the JSON parsing and setText() code into the thread's run() method after the HTTP request is made but since running UI-related code (in this case setText()) in a separate thread is not allowed you can use a Handler to schedule setText() to run in the UI thread.

You can read the basics on AsyncTask and Handler here.

Piovezan
  • 3,215
  • 1
  • 28
  • 45
  • 1
    Joining threads is not a good solution because the main (UI) thread still becomes occupied needlessly waiting for the other thread to finish. You may face ANR issues if the HTTP request takes too much time. – Piovezan Nov 08 '13 at 10:25
1

When you spawn a thread, code execution splits into different time frames, so even though global scope is shared, you won't get objects populated in a timely fashion for your UI update task if you don't implement some logic to prevent inconsistencies.

Android provides multiple flow control and inter-thread communication patterns built-in that can help you solve such inconsistencies. One such option involves AsyncTask, in your case you can do the following:

  1. Extended AsyncTask with your UI thread-forbidden tasks inside the doInBackground() method;
  2. Get logic that needs to run on UI thread (such as manipulating Views) inside onPostExecute() handler from the same AsyncTask instance. This handler will only be called after doInBackground returns, so the program knows that the logic to populate the object was triggered.

You can look up a sample of AsyncTask in this answear for a practical approach.

Note: If you want to use parent class members such as findViewByID inside an AsyncTask instance, you will need to manually invoke the parent file scope using the <UIThreadName>.this., e.g. <UIThreadName>.this.findViewByID(id). You can do this freely in onPostExecute which has no restrictions due to running on the UI thread, but you are restricted to not performing UI changes in doInBackground (which doesn't run on the UI thread).

Community
  • 1
  • 1
leRobot
  • 1,497
  • 1
  • 18
  • 30
0

I solved it, I just added t.join after the thread declaration :)

ruaa.brkat
  • 41
  • 1
  • 8