Search code examples
javaandroidandroid-asynctasknetworkonmainthread

How do I get editText and perform network operations on it?


My program just needs to be able to take a travel time based on what is output from Google's Directions API. I plan on doing more with that number, but for now, I'd like to just be able to display it. Here's the meat of the code:

public class DirectionDuration {

public DirectionDuration() {

}

@SuppressWarnings("deprecation")
public Document getDocument(String url) {

    try {
        URL u = new URL(url);
        URLConnection connection = u.openConnection();
        InputStream in = (InputStream) connection.getContent();
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document doc = builder.parse(in);
        return doc;
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ParserConfigurationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (SAXException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}

public int getDurationValue (Document doc) //Used to read the travel time from the XML file
{
    NodeList nl1 = doc.getElementsByTagName("duration");
    Node node1 = (Node) nl1.item(nl1.getLength() - 1);
    NodeList nl2 = node1.getChildNodes();
    Node node2 = (Node) nl2.item(getNodeIndex(nl2, "value"));
    Log.i("DurationValue", node2.getTextContent());
    return Integer.parseInt(node2.getTextContent());
}

private int getNodeIndex(NodeList nl, String nodename) {
    for(int i = 0 ; i < nl.getLength() ; i++) {
        if(nl.item(i).getNodeName().equals(nodename))
            return i;
    }
    return -1;
}
}

Here's my main class:

public class MainActivity extends ActionBarActivity {

private String start = null;
private String end = null;
private String mode = null;
private int baseline = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final EditText st = (EditText) findViewById(R.id.st);
    final EditText en = (EditText) findViewById(R.id.en);
    Button button1 = (Button) findViewById(R.id.button);
    button1.setOnClickListener(new View.OnClickListener(){

        @Override
        public void onClick(View v) {
            start = st.getText().toString();
            end = en.getText().toString();
            mode = "driving";
            String url = "http://maps.googleapis.com/maps/api/directions/xml?"
                    + "origin=" + start
                    + "&destination=" + end
                    + "&sensor=false&units=metric&mode="+ mode;
            new DirectionAsync().execute(url);
        }
    });
}

private class DirectionAsync extends AsyncTask<String, Void, Integer>
{
    @Override
    protected Integer doInBackground(String... urls)
    {
        GMapV2Direction md = new GMapV2Direction();
        Document doc = md.getDocument(urls[0]);
        int duration = md.getDurationValue(doc);
        return duration;
    }

    @Override
    protected void onPostExecute(Integer result)
    {
        baseline = result;
        TextView res = (TextView) findViewById(R.id.res);
        res.setText((result / 3600) + " hours " + ((result % 3600) / 60) + " minutes " + (result % 60) + " seconds");
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

}

Problem resolved.


Solution

  • Let me suggest an outline of how you should restructure your code.

    Your setOnClickListener and onClick should be setup when you are creating the view, onCreateView, and not in the async task.

    Within onClick you will want to create a new async task that makes the http call: new DirectionsAsync(...).execute();

    Within doInBackground() you make the URL connection and get your result. As a return from doInBackground() you hand off the duration you have received to onPostExecute() which is also in the async task.

    The code in onPostExecute() runs on the UI thread and it is there that you can write the result to your interface with the res.setText()

    Sorry but I didn't have time to write code or pseudo-code for this answer, but I hope this outline will help you make some progress.

    An easy way to pass variables to the async task is in its constructor:

    public class DirectionsAsync extends AsyncTask <String, Void, Integer> {
    
    String startPoint;
    String endPoint;
    
    public DirectionsAsync(String start, String end) {
        startPoint = start;
        endPoint = end;
    }
    

    and then doInBackground references startPoint and endPoint.