我正在尝试使用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);
}
}
当我从我的MainActivity调用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
时,我是否需要在单独的线程中进行网络操作?
答案 0 :(得分:2)
您应该通过覆盖onHandleIntent()
方法在不同的主题上进行处理,而不应覆盖onStartCommand()
修改
您可以看到here IntentService如何为您处理onStartCommand,因此您不必这样做。
答案 1 :(得分:1)
一般情况下,你不能在主线程(UI线程)中进行网络调用,因此你得到NetworkOnMainThreadException。
IntentService确实从主线程中卸载了任务。但是你必须实现multiprocessing.Pipe()
。
检查文档:
请记住,任务将按顺序处理。如果你更灵活的控制使用原始服务并自己管理线程。
答案 2 :(得分:1)
如文档中所述:
您不应该为IntentService重写此方法。相反,覆盖onHandleIntent(Intent),系统在IntentService收到启动请求时调用。
似乎onStartCommand用在mainthread上,而onHandleIntent是在工作线程上处理的:
这个"工作队列处理器"模式通常用于从应用程序的主线程卸载任务。存在IntentService类以简化此模式并处理机制。要使用它,请扩展IntentService并实现onHandleIntent(Intent)。 IntentService将接收Intents,启动工作线程,并根据需要停止服务。
https://developer.android.com/reference/android/app/IntentService.html https://developer.android.com/reference/android/app/IntentService.html#onStartCommand(android.content.Intent, int, int)
答案 3 :(得分:0)
您的代码应该在
中执行onHandleIntent()
方法。这是用于生成工作线程并对其进行操作的方法。
我还建议尝试将你的工作转移到
JobIntentService
由于Android O及以上版本有限制,当app不在前台或有任何可见组件时调用startService会引发异常。
JobIntentService与IntentService完全相似。不同之处在于它将在支持JobScheduler的设备上内部使用JobScheduler api。只需覆盖
即可onHandleWork
方法并像使用IntentService一样使用它。使用
enqueueWork
开始工作而不是startService