如何在Android上使用网络I / O.

时间:2016-07-29 20:20:00

标签: java android

以下课程的目的是从不同新闻网站的不同文章中获取文本。下面的版本是为Android设计的,但它在运行时会抛出NetworkOnMainThread异常。当我使用这个类的早期版本,专门在计算机上运行时,它工作正常,但我不确定网络I / O如何在Android上运行。我已经看到了关于这个主题的一些问题的其他答案,但我不明白为什么在Android中该程序引发异常,但在桌面上它工作正常。谁能解释一下?

package com.example.user.helloworld;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

public class ArticleReceiver {

private ArrayList<Article> newsArticles = new ArrayList<>();
private ArrayList<String> newsLinks = new ArrayList<>();

public ArticleReceiver(int numArticles, String link) {
    if (numArticles != 0) {
        receiveNewsArticles(numArticles, link);
    }else{
        System.out.println("ERROR: numArticles request for " + link + " cannot equal 0.");
    }
}

private void receiveNewsArticles(int numArticles, String urlAddress) {
    URL rssUrl = null;
    // if connected to Internet
    if (true){//isInternetAvailable()) {
        try {
            // gather links
            rssUrl = new URL(urlAddress);
            BufferedReader in = new BufferedReader(new InputStreamReader(rssUrl.openStream()));
            String line;

            // fix bbc trash urls
            if (urlAddress.equals(Main.BBC_URL)) {
                numArticles++;
            }

            while ((line = in.readLine()) != null && newsLinks.size() <= numArticles) {
                if (line.contains("<link>")) {
                    // find links through tags
                    int firstPos = line.indexOf("<link>");
                    String temp = line.substring(firstPos);
                    temp = temp.replace("<link>", "");
                    int lastPos = temp.indexOf("</link>");
                    temp = temp.substring(0, lastPos);

                    newsLinks.add(temp);
                }
            }

            in.close();

            // test if there are links and if there is remove first
            // unnecessary
            // link
            if (!newsLinks.isEmpty()) {
                if (urlAddress.equals(Main.BBC_URL)) {
                    newsLinks.remove(0);
                    newsLinks.remove(0);
                }else if(urlAddress.equals(Main.CNN_URL) || urlAddress.equals(Main.FOX_URL) || urlAddress.equals(Main.ESPN_URL)){
                    newsLinks.remove(0);
                }
            } else {
                System.out.println("ERROR: No Found Articles. Check If You Have Wifi.");
            }

            // gather articles from HTML "section" or "p" tag of article using Jsoup
            for (String newsLink : newsLinks) {
                // get webpage
                Document doc = Jsoup.connect(newsLink).get();

                // get article from different websites
                String article = null;
                if (urlAddress.equals(Main.FOX_URL)) {
                    Elements element = doc.select("p");
                    article = element.text();
                } else if (urlAddress.equals(Main.CNN_URL)) {
                    Elements element = doc.select("section");
                    article = element.text();
                } else if (urlAddress.equals(Main.BBC_URL)) {
                    Elements element = doc.select("p");
                    article = element.text();
                }else if(urlAddress.equals(Main.ESPN_URL)){
                    Elements element = doc.select("p");
                    article = element.text();
                }

                newsArticles.add(new Article(article, Main.SUMMARY_SENTENCES));
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    } else {
        System.out.println("ERROR: No internet connection established.");
        return;
    }
}

public ArrayList<Article> getArticles() {
    return newsArticles;
}

public Article getArticle(int i) {
    if (newsArticles.size() <= i) {
        return null;
    } else {
        return newsArticles.get(i);
    }
}

//The method below does not recognize the "getSystemService" method, and when the method is no longer present there is a NetworkOnMainThreadException
private boolean isInternetAvailable() {
    ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

}

1 个答案:

答案 0 :(得分:0)

您需要异步执行Web服务连接。 我在我的项目中使用的是ApiConnection类和接口get响应。例如:

Apiconnection class

public class APIConnection extends AsyncTask<Object, String, Void> {

    private final String TAG = "API-CONNECTION";
    private StringBuilder sbuilder;
    private JSONObject json;
    private APIConnectionInterface mInterface;
    protected int httpResponseCode = 0;
    private String entity = null, url;
    private APIConnectionType mmode;
    private boolean DEBUG = BuildConfig.DEBUG;

    private String[][] headers;

    /**
    Constructor For APIConnection
     */
    public APIConnection(APIConnectionInterface thisdelegate, APIConnectionType mode, String murl, String entity) {
        this.mInterface     = thisdelegate;
        this.mmode          = mode;
        this.url            = murl;
        this.entity         = entity;
        initHeaders();
    }

    private void initHeaders(){
            headers = new String[][]{
                    {"token", "MY_TOKEN"},
                    {"Content-Type", "application/json;charset=utf-8"},
                    {"user-agent", "android"},
                    {"Accept-Language", "es"}
            };
    }

    @Override
    protected Void doInBackground(Object... params) {
        BufferedReader buffer = null;
        InputStreamReader in = null;
        OutputStream os = null;

        int timeoutConnection = 30000, timeoutSocket = 20000;

        try{
            sbuilder = new StringBuilder();

            url = convertURL(url);
            if (entity==null)entity="{}";
            URL u = new URL(url);
            HttpURLConnection conn;
            if (url.startsWith("https://")) 
        conn = (HttpsURLConnection) u.openConnection();
            else 
        conn = (HttpURLConnection) u.openConnection();

            conn.setReadTimeout(timeoutConnection);
            conn.setConnectTimeout(timeoutSocket);

            for (String[] arr : headers){ conn.addRequestProperty(arr[0], arr[1]); }

    /*GET*/if (mmode == APIConnectionType.GET) {
                conn.setDoInput(true);
                conn.setRequestMethod(mmode.toString());
                httpResponseCode = conn.getResponseCode();

                in = new InputStreamReader(
                        httpResponseCode == HttpURLConnection.HTTP_OK ? conn.getInputStream() : conn.getErrorStream(),"UTF-8");

    /*OTHER*/} else if (mmode == APIConnectionType.POST || mmode == APIConnectionType.PUT ||
                    mmode == APIConnectionType.PATCH || mmode == APIConnectionType.DELETE) {

                    conn.setRequestMethod(mmode.toString());
                    conn.setDoOutput(true);

                    byte[] outputInBytes = entity.getBytes("UTF-8");
                    os = conn.getOutputStream();
                    os.write( outputInBytes );

                    httpResponseCode = conn.getResponseCode();

                    in = new InputStreamReader(
                            httpResponseCode == HttpURLConnection.HTTP_OK ? conn.getInputStream() : conn.getErrorStream(), "UTF-8");
            }
            if (in!=null){
                buffer=new BufferedReader(in);
                String line;
                while ((line = buffer.readLine()) != null) {
                    sbuilder.append(line);
                }
            }else {
                sbuilder.append("");
            }

        }
        catch(IOException e) {
            if (DEBUG)Log.d(TAG, "onBackground Exception " + e.getMessage());
            sbuilder= new StringBuilder();
            httpResponseCode = 0;
            cancel(true);
            return null;
        } finally {
            if (buffer != null) {
                try {
                    buffer.close();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }
            if (os!=null){
                try {
                    os.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result){
        try{
            if (DEBUG) timelapse_e = System.currentTimeMillis();
            if (sbuilder != null) {
                    json = new JSONObject(sbuilder.toString());

            }

            if (sbuilder != null){
                sbuilder.setLength(0);
                sbuilder.trimToSize();
            }

            sbuilder = null;
            GoRunning();
            hideDialog();
        }
        catch(RuntimeException e) {
            if (DEBUG)Log.d(TAG, "PostExecute RuntimeException " + e.getMessage());
            cancel(true);
        }
        catch(Exception e) {
            if (DEBUG)Log.d(TAG, "PostExecute Exception " + e.getMessage());
            cancel(true);
        }

    }

    @Override protected void onCancelled() {
        if (mInterface != null) mInterface.onCancelled(APIConnection.this);
        super.onCancelled();
    }

    @Override protected void onPreExecute() {
        super.onPreExecute();
        if (DEBUG) timelapse_s = System.currentTimeMillis();
        if (mInterface != null) mInterface.onStartLoading(APIConnection.this);
    }

    public void GoRunning(){
        if (mInterface != null) try {
            mInterface.onDataArrival(APIConnection.this, json, httpResponseCode);
        } catch (JSONException e) {
            onCancelled();
            e.printStackTrace();
        }
    }

    /**
     * Hide Dialog (Progress dialog) if is showing and activity NOT Finishing
     */
    private void hideDialog() {
        if (mInterface != null) mInterface.onFinishedLoading(APIConnection.this);
    }

    /** <b>convertURL(String str);</b><br/>
     * replaces any special characters to <b>%??</b><br/>
     * Replacements actived:<br/>
     * "{Space}" ==> "%20"
     * @param str URL to encode
     * @return url encoded
     */
    public static String convertURL(String str) {

        return str.trim().replace(" ", "%20");
            //              .replace("&", "%26")
            //              .replace(",", "%2c").replace("(", "%28").replace(")", "%29")
            //              .replace("!", "%21").replace("=", "%3D").replace("<", "%3C")
            //              .replace(">", "%3E").replace("#", "%23").replace("$", "%24")
            //              .replace("'", "%27").replace("*", "%2A").replace("-", "%2D")
            //              .replace(".", "%2E").replace("/", "%2F").replace(":", "%3A")
            //              .replace(";", "%3B").replace("?", "%3F").replace("@", "%40")
            //              .replace("[", "%5B").replace("\\", "%5C").replace("]", "%5D")
            //              .replace("_", "%5F").replace("`", "%60").replace("{", "%7B")
            //              .replace("|", "%7C").replace("}", "%7D"));
    }

    public interface APIConnectionInterface {
        void onDataArrival(APIConnection apiConnection, JSONObject json, int httpResponseCode) throws JSONException;
        void onStartLoading(APIConnection apiConnection);
        void onFinishedLoading(APIConnection apiConnection);
        void onCancelled(APIConnection apiConnection);
    }

    public enum APIConnectionType {
        GET("GET"),
        POST("POST"),
        PUT("PUT"),
        PATCH("PATCH"),
        DELETE("DELETE");
        private String methodName;
        APIConnectionType(String methodName){this.methodName = methodName;}
        @Override public String toString() {return methodName;}
    }

}

然后从任何Activity或Fragment我可以调用web服务async

像这样:

new APIConnection(new APIConnection.APIConnectionInterface() {
            @Override public void onDataArrival(APIConnection apiConnection, JSONObject json, int httpResponseCode) {
                try {
                    if (isHttpResponseOk(httpResponseCode, json)){//200 or 201

                        JSONObject obj = json.getJSONObject("results");
                       // do things with json

                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            @Override public void onStartLoading(APIConnection apiConnection) {showProgressDialog();}
            @Override public void onFinishedLoading(APIConnection apiConnection) {hideProgressDialog();}
            @Override public void onCancelled(APIConnection apiConnection) {hideProgressDialog();}
        }, APIConnection.APIConnectionType.GET, MyApp.API_URL + "/master_data/", null).execute();

您唯一需要的是使响应适应您需要的其他对象。

我希望有帮助