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