Android:在服务中使用网络

12
在我的Android应用程序的Service类中调用REST WebService会导致NetworkOnMainThreadException异常。
我理解为什么在Activity中会引发此异常:同步从网络中获取数据非常糟糕,但是我很惊讶在Service类中也会出现同样的错误。 所以我的问题是:
- 在这种特定情况下,我是否应该使用StrictMode.setThreadPolicy()来允许此调用。(对于那些因在Activity中遇到此错误而阅读此内容的人,请不要使用StrictMode隐藏此错误,而应使用AsyncTask)
- 还是应该使用AsyncTask?在这种情况下的问题是什么?服务不是在与Activity的线程隔离的线程上运行吗?
2个回答

18

虽然服务旨在进行后台处理,但它们仍运行在主线程中。

摘自文档的简短引用:

注意:默认情况下,服务在声明它的应用程序进程中的主线程中运行。因此,如果您的服务在用户与同一应用程序的活动交互时执行密集或阻塞操作,则服务将减慢活动性能。为避免影响应用程序性能,您应在服务内部启动新线程。

'后台处理'意味着服务没有用户界面,即使用户没有直接与应用程序交互也可以运行。但所有后台处理仍然默认在主线程中进行。

那么如何解决这个问题并摆脱异常?正如文档建议的那样,您必须使用后台线程。在您的服务中,您可以使用AsyncTask或直接创建线程。但我想IntentService可能是您的最佳选择。IntentService在后台线程中处理请求(所以这就是您要寻找的服务类型)。


感谢您的回答,这正是我怀疑的。我以为因为它们用于后台任务,服务默认会在另一个线程上运行,但事实并非如此。实际上,我使用该服务来管理对“MediaPlayer”的调用,因此将其放在主线程上似乎不会成为问题,因为“prepareAsync()”使我能够优雅地管理其行为。 我只需要修改我的服务,以便使用“AsyncTask”获取流媒体URL即可。 - Teovald
2
好的回答,还有一些材料可供使用,可以帮助您了解如何有效地使用网络,以确保您的应用程序得到优化。http://developer.att.com/developer/forward.jsp?passedItemId=7200042 - Rod Burns

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

}

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接