如何解决android.os.networkonmainthreadexception

时间:2016-03-20 10:34:16

标签: android

我是android的新手,我正在尝试从服务器读取数据。我使用一个util并像这样调用那个

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

但我得到android.os.networkonmainthreadexception。我怎样才能减少呢?

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;
    }

}

1 个答案:

答案 0 :(得分:0)

首先,我不建议再使用HTTPClient,因为sdk版本23不再支持它。

因此,最好将网络操作迁移到URL连接。

现在,android永远不允许在主线程上进行网络操作,因为它会在相当长的时间内阻塞UI线程,因此可能导致崩溃或糟糕的用户体验。

您可以查看以下文档:Doc 1

更好的网络操作方法是创建AsyncTask

请注意不要访问doInBackground方法中的任何UI线程元素。您可以在onPreExecute或onPostExecute方法上修改UI线程元素。

我创建了一个NetworkOps Util。您可以查看一下,无论它对您有用:

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;
    }


}

从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
            }

    }
}

您还可以使用PostData函数发布数据。在方法doInBackground中,添加:

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

Source = NetworkOps.PostData(getApplicationContext(), url, builder);