2016-07-29 16 views
-1

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

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

}

+3

您需要在单独的线程中进行调用。 AsyncTask,Loader,Thread ..... –

回答

0

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

Apiconnection类

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

} 

然后从任何活动或片段,我可以调用Web服务异步

这样的:

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(); 

你需要的仅仅是将响应调整为您需要的其他对象。

我希望能够帮助

相关问题