Android 在IntentService中运行任务时出现NetworkOnMainThreadException

Android 在IntentService中运行任务时出现NetworkOnMainThreadException,android,multithreading,intentservice,Android,Multithreading,Intentservice,我正在尝试使用IntentService执行文件下载任务。我了解到IntentService将创建一个工作线程并执行请求的任务。下面的代码将下载一个视频文件 public class MyServiceUsingIntentService extends IntentService{ private int count=0; public MyServiceUsingIntentService() { super("MyServiceUsingIntentSe

我正在尝试使用IntentService执行文件下载任务。我了解到IntentService将创建一个工作线程并执行请求的任务。下面的代码将下载一个视频文件

public class MyServiceUsingIntentService extends IntentService{

    private int count=0;

    public MyServiceUsingIntentService() {
        super("MyServiceUsingIntentService");
    }

    public MyServiceUsingIntentService(String name) {
        super("MyServiceUsingIntentService");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

                try {
                    URL url = new URL("http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4");
                    URLConnection urlConnection = url.openConnection();
                    urlConnection.setReadTimeout(5000);

                    debugMessage("urlConnection.getContentLength : " + urlConnection.getContentLength());

                    InputStream readStream = urlConnection.getInputStream();
                    String filename = "/sdcard/sample" + count++ +".mp4";
                    OutputStream writeStream = new FileOutputStream(filename);
                    int i;
                    byte[] byteArray = new byte[153600];
                    while((i = readStream.read(byteArray)) != -1){
                        writeStream.write(byteArray,0,i);
                    }
                    writeStream.close();
                    readStream.close();

                    debugMessage("Download done in doInBackground");
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }    
        return START_STICKY;
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {

    }

    public static void debugMessage(String message){
        Log.d("MyServiceUsingIntentService",message);
    }

}
当我从主活动调用startService时

startService(new Intent(MainActivity.this, MyServiceUsingIntentService.class));
我正在获取NetworkOnMainThreadException错误:

12-30 23:51:04.305 9586-9586/oneplus.app7 D/AndroidRuntime: Shutting down VM
12-30 23:51:04.306 9586-9586/oneplus.app7 E/AndroidRuntime: FATAL EXCEPTION: main
                                                            Process: oneplus.app7, PID: 9586
                                                            java.lang.RuntimeException: Unable to start service oneplus.app7.MyServiceUsingIntentService@be390c with Intent { cmp=oneplus.app7/.MyServiceUsingIntentService }: android.os.NetworkOnMainThreadException
                                                                at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3479)
                                                                at android.app.ActivityThread.-wrap21(ActivityThread.java)
                                                                at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1657)
                                                                at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                at android.os.Looper.loop(Looper.java:154)
                                                                at android.app.ActivityThread.main(ActivityThread.java:6334)
                                                                at java.lang.reflect.Method.invoke(Native Method)
                                                                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                                                                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
                                                             Caused by: android.os.NetworkOnMainThreadException
                                                                at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1303)
                                                                at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:86)
                                                                at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:74)
                                                                at java.net.InetAddress.getAllByName(InetAddress.java:752)
                                                                at com.android.okhttp.internal.Network$1.resolveInetAddresses(Network.java:29)
                                                                at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:187)
                                                                at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:156)
                                                                at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:98)
                                                                at com.android.okhttp.internal.http.HttpEngine.createNextConnection(HttpEngine.java:346)
                                                                at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:329)
                                                                at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:247)
                                                                at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:457)
                                                                at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:405)
                                                                at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getHeaders(HttpURLConnectionImpl.java:162)
                                                                at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getHeaderField(HttpURLConnectionImpl.java:206)
                                                                at java.net.URLConnection.getHeaderFieldLong(URLConnection.java:628)
                                                                at java.net.URLConnection.getContentLengthLong(URLConnection.java:500)
                                                                at java.net.URLConnection.getContentLength(URLConnection.java:484)
                                                                at oneplus.app7.MyServiceUsingIntentService.onStartCommand(MyServiceUsingIntentService.java:54)
                                                                at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3462)
                                                                at android.app.ActivityThread.-wrap21(ActivityThread.java) 
                                                                at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1657) 
                                                                at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                at android.os.Looper.loop(Looper.java:154) 
                                                                at android.app.ActivityThread.main(ActivityThread.java:6334) 
                                                                at java.lang.reflect.Method.invoke(Native Method) 
                                                                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
                                                                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 
但如果我尝试在
onStartCommand()
内的线程中运行下载部分,它工作正常,并且我能够下载文件


如果每次使用
IntentService
,是否需要在单独的线程中执行网络操作

您应该通过重写
onHandleIntent()
方法在不同的线程上进行处理,而不应该重写
onStartCommand()

编辑


您可以看到IntentService如何为您处理onStart命令,因此您不必这样做。

您的代码应该在

onHandleIntent()
方法。这是用于生成工作线程并对其执行工作的方法

我还建议你试着把你的工作转移到

JobIntentService
由于Android O及以上版本将有一个限制,当应用程序不在前台或有任何可见组件时调用startService将引发异常

JobIntentService与IntentService完全相似。区别在于它将在支持JobScheduler的设备上内部使用JobScheduler api。只需覆盖

onHandleWork
方法,并像使用IntentService一样使用它。使用

enqueueWork 

一般来说,要启动工作而不是startService,您不能在主线程(UI线程)中进行网络调用,因此会出现NetworkOnMainThreadException

IntentService确实从主线程卸载任务。但是您必须实现
onHandleIntent(Intent)

检查文件:


请记住,任务将按顺序处理。如果您需要更灵活的控制,请使用原始服务并自行管理线程。

如文档中所述:

启动命令 您不应该为您的IntentService重写此方法。相反,重写onHandleIntent(Intent),当IntentService接收到启动请求时,系统会调用它

似乎在主线程上使用onStartCommand,而在工作线程上处理onHandleIntent:

这种“工作队列处理器”模式通常用于从应用程序的主线程卸载任务。IntentService类的存在是为了简化此模式并处理机制。要使用它,请扩展IntentService并实现onHandleIntent(Intent)。IntentService将接收意图,启动工作线程,并根据需要停止服务

裁判

您能告诉我为什么在IntentService中有onStartCommand()方法吗?似乎onStartCommand在IntentService中是无用的。如果我错了,请纠正我。IntentService只是服务类的一个子类,所以您继承了服务类的所有方法,包括onStartCommand,但IntentService不是自己处理线程,而是在后台threadonHandleIntent()上为您提供onHandleIntent的实用方法没有接到电话以防万一。知道为什么吗?您是否删除了对所有其他service onStart方法的覆盖?onStart()和onStart命令?谢谢,这非常有用。竖起大拇指。@JoxTraex:问题很清楚,为什么IntentService会出现NetworkOnMainThreadException。我不接受这是重复的。因为IntentService声称在工作线程上运行。