在我的Android应用的Service类中调用REST WebService会创建NetworkOnMainThreadException
。
我理解为什么在Activity中引发这个异常:同步通过网络获取内容是一种非常糟糕的做法,但我很惊讶在服务类中看到相同的错误。 所以我的问题是:
- 在这种特定情况下,我应该使用StrictMode.setThreadPolicy()
来允许此呼叫。 (对于读取此内容的人,因为他们在活动中遇到此错误,请不要使用StrictMode隐藏此错误,请使用AsyncTask)
- 或者我应该使用AsyncTask吗?在那种情况下,这里的问题是什么?线程上的服务不是与Activity分开的吗?
答案 0 :(得分:15)
即使Service用于后台处理,它们也会在主线程中运行。
来自documentation的简短引用:
警告:默认情况下,服务在与声明它的应用程序相同的进程中运行,并在该应用程序的主线程中运行。因此,如果您的服务在用户与同一应用程序中的活动进行交互时执行密集或阻止操作,则该服务将降低活动性能。为避免影响应用程序性能,您应该在服务中启动一个新线程。
“后台处理”意味着服务没有用户界面,即使用户没有直接与应用程序交互,它也可以运行。但默认情况下,所有后台处理仍然在主线程中发生。
那么,如何解决它并摆脱异常呢?正如文档所示,您必须使用后台线程。在您的服务中,您可以使用AsyncTask
或直接创建线程。但我猜IntentService可能是最适合您的情况。 IntentService
处理后台线程中的请求(这是您正在寻找的服务类型)。
答案 1 :(得分:0)
服务在主线程中运行,这就是为什么你需要做类似
的事情public class ServiceDownloadSomething extends Service {
private static final String TAG = ServiceDownloadSomething.class.getSimpleName();
private boolean isRunning;
private Thread backgroundThread;
private Runnable myTask = new Runnable() {
public void run() {
while (true) {
//sleep 30 seconds
long sleepTime = System.currentTimeMillis() + (15 * 1000);
try {
Thread.sleep(sleepTime - System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
//perform network action
downloadSomething();
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
this.isRunning = false;
this.backgroundThread = new Thread(myTask);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(!this.isRunning) {
this.isRunning = true;
this.backgroundThread.start();
}
return START_STICKY;
}
@Override
public void onDestroy() {
this.isRunning = false;
}
private void downloadSomething() throws IOException {
URL url = new URL("http://192.168.197.101:8080/api/medias/");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("POST");
conn.setDoInput(true);
// Starts the query
conn.connect();
InputStream is = conn.getInputStream();
StringBuilder sb = new StringBuilder();
int r;
do {
r = is.read();
if (r != -1){
sb.append((char) r);
}
} while (r != -1);
String json = sb.toString();
Log.d(TAG, json);
}
}