以下课程的目的是从不同新闻网站的不同文章中获取文本。下面的版本是为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();
}
}
答案 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();
您唯一需要的是使响应适应您需要的其他对象。
我希望有帮助