0

I am new to android and I am trying to read data from a server. I use a util and call that util like this

private void ParseSource(String Url){
   String source = new Cls_SourceGrabber().grabSource(Url);
} 

But I am getting a android.os.networkonmainthreadexception. How can I reduce that?

My SourceGrabber util:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

public class Cls_SourceGrabber {
    private HttpGet mRequest;
    private HttpClient mClient;
    private BufferedReader mReader;

    private StringBuffer mBuffer;
    private String mNewLine;

    public Cls_SourceGrabber() {
        mRequest = new HttpGet();
        InitializeClient();
        mReader = null;

        mBuffer = new StringBuffer(10000);
        mNewLine = System.getProperty("line.separator");
    }

    private void InitializeClient() {
        if (mClient == null || mClient.getConnectionManager() == null) {
            HttpParams httpParameters = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(httpParameters, 4500);
            HttpConnectionParams.setSoTimeout(httpParameters, 10000);
            // HttpConnectionParams.setTcpNoDelay(httpParameters, true);
            mClient = new DefaultHttpClient(httpParameters);
        }
    }

    /*
     *Grab the full source
     */
    public String grabSource(String url) {
        mBuffer.setLength(0);
        InitializeClient();
        String source = "";
        try {
            mRequest.setURI(new URI(url));
            HttpResponse response = mClient.execute(mRequest);
            mReader = new BufferedReader(new InputStreamReader(response
                    .getEntity().getContent()));

            String line = "";
            while ((line = mReader.readLine()) != null) {
                mBuffer.append(line);
                mBuffer.append(mNewLine);
                source = mBuffer.toString();
                if (Thread.interrupted()) {
                    break;
                }
            }
        } catch (ConnectTimeoutException e) {
            source = "Connection Timed Out.";
        } catch (java.net.UnknownHostException e) {
            source = "No Internet Connection available!";
        } catch (java.lang.ArrayIndexOutOfBoundsException e) {
            source = "Site Parsing Exception.";
        } catch (ClientProtocolException e) {
            source = "Protocol Exception.";
        } catch (IOException e) {
            source = "Server not responding.";
        } catch (URISyntaxException e) {
            source = "Wrong URL!";
        } catch (Exception e) {
            source = "Exception - " + e.toString() + " - "
                    + e.getMessage();
            e.printStackTrace();

        } finally {
            closeReader();
        }
        return source;
    }

}
Arun Shankar
  • 2,603
  • 2
  • 26
  • 36
  • 2
    Possible duplicate of [How to fix android.os.NetworkOnMainThreadException?](http://stackoverflow.com/questions/6343166/how-to-fix-android-os-networkonmainthreadexception) – Arun Shankar Mar 20 '16 at 10:36
  • 1
    Do your network code in async task class or in service. You should not write network code in main thread. – Talha Mar 20 '16 at 10:39

1 Answers1

0

First of all, I would not recommend on using HTTPClient any more, since it is not supported any more from sdk version 23.

So, it will be better to migrate the network operations to URL Connection.

Now, android never allows network operations on Main thread since it will block the UI thread for a considerable time, hence may cause crash or bad user experience.

You can take a look on these docs : Doc 1

The better way to do Network operations is by creating an AsyncTask.

Just take care not to access any UI thread element in the doInBackground method. You can modify UI Thread elements on onPreExecute or onPostExecute Methods.

I have created a NetworkOps Util. You can take a look on that, whether it may be any use for you :

import android.content.Context;
import android.net.Uri;
import android.util.Log;

import com.csehelper.variables.Constants;
import com.csehelper.variables.Keys;
import com.csehelper.variables.Url;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.ArrayList;

public class NetworkOps {
    public final String EXCEPTION = "~Exception~";
    /****************************
     * Method to Grab Source
     ****************************/
    public static String GrabSource(String URL) {
        return PostData(URL, null);
    }



    /**
     * *****************************************
     * Method to Grab Source code from URL
     * Posting Data
     * *****************************************
     */
    private static String PostData(String url, Uri.Builder uribuilder) {
        String Source;
       HttpURLConnection.setFollowRedirects(false);
        HttpURLConnection urlConnection = null;
        try {
            urlConnection = (HttpURLConnection) new URL(url).openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setConnectTimeout(10000);

            if(uribuilder != null) {
                String query = uribuilder.build().getEncodedQuery();

                OutputStream os = urlConnection.getOutputStream();
                BufferedWriter writer = new BufferedWriter(
                        new OutputStreamWriter(os, "UTF-8"));
                writer.write(query);
                writer.flush();
                writer.close();
                os.close();
            }

            urlConnection.connect();

            if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {

                String line;
                StringBuilder builder = new StringBuilder();
                InputStreamReader isr = new InputStreamReader(
                        urlConnection.getInputStream());
                BufferedReader reader = new BufferedReader(isr);
                while ((line = reader.readLine()) != null) {
                    builder.append(line);
                }
                Source = builder.toString();
            } else {
                Source = EXCEPTION + "Server unreachable. Check network connection.";
            }
        } catch (SocketTimeoutException e) {
            Source = EXCEPTION + "Connection timed out.";
        } catch (java.net.UnknownHostException e) {
            Source = EXCEPTION + Constants.EXCEPTION_NO_NET;
        } catch (ArrayIndexOutOfBoundsException e) {
            Source = EXCEPTION + "Server error";
        } catch (ProtocolException e) {
            Source = EXCEPTION + "Protocol error";
        } catch (IOException e) {
            Source = EXCEPTION + "Server unreachable. Check network connection.";
        } catch (Exception e) {
            Source = EXCEPTION + "Error:" + e.toString() + " - "
                    + e.getMessage();
            e.printStackTrace();

        } finally {
            if (urlConnection != null) urlConnection.disconnect();
        }
        return Source;
    }


}

Call these Static Functions from AsyncTask:

/*********************************
 * AsyncTask to GrabSource
 ********************************/
class AsyncTask_GrabSource extends AsyncTask<Void, Void, Void> {

    String Source = null;
    String url = "https://enigmatic-woodland-35608.herokuapp.com/pager.json";
    @Override
    protected void onPreExecute() {
       //Runs on Main Thread. You can access your UI elements here.
    }

    @Override
    protected Void doInBackground(Void... params) {
        // Don't access any UI elements from this function
        Source = NetworkOps.GrabSource(this.url);
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        if (Source != null) {
            if (!Source.contains("~Exception~")) {
                //Show Error Message or do whatever you want
            } else {
                //Do Whatever with your Grabbed Sourcecode.
                // This function runs on UI Thread, so you can update UI elements here
            }

    }
}

You can also post data with the function PostData. In method doInBackground, add this:

Uri.Builder builder = new Uri.Builder()
                    .appendQueryParameter("key", "value")
                    .appendQueryParameter("key2", "value2");

Source = NetworkOps.PostData(getApplicationContext(), url, builder);
Arun Shankar
  • 2,603
  • 2
  • 26
  • 36