multithreading - Android: NetworkOnMainThreadException occurs when using retrofit in a new thread? -
i try use retrofit library download file(apk:2mb)from url in separated thread.
here's code(see tutorial:https://futurestud.io/blog/retrofit-2-how-to-download-files-from-server):
public class mainactivity extends appcompatactivity { string fileurl = "....."; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); new thread(new runnable() { @override public void run() { filedownloadservice downloadservice = servicegenerator.createservice(filedownloadservice.class); call<responsebody> call = downloadservice.downloadfilewithdynamicurlsync(fileurl2); call.enqueue(new callback<responsebody>() { @override public void onresponse(call<responsebody> call, response<responsebody> response) { if (response.issuccessful()) { writeresponsebodytodisk(response.body()); } else { log.d("fail", "server contact failed"); } } @override public void onfailure(call<responsebody> call, throwable t) { log.e("fail", "error"); } }); } }).start(); } private boolean writeresponsebodytodisk(responsebody body) { try { file apkfile = new file(getexternalfilesdir(null) + file.separator + "test.apk"); inputstream inputstream = null; outputstream outputstream = null; try { byte[] filereader = new byte[4096]; inputstream = body.bytestream(); outputstream = new fileoutputstream(apkfile); while (true) { int read = inputstream.read(filereader); if (read == -1) { break; } outputstream.write(filereader, 0, read); } outputstream.flush(); return true; } catch (ioexception e) { e.printstacktrace(); return false; } { if (inputstream != null) { inputstream.close(); } if (outputstream != null) { outputstream.close(); } } } catch (ioexception e) { e.printstacktrace(); return false; } } }
the code of service:
public class servicegenerator { public static final string api_base_url = "https://your.api.url/"; private static okhttpclient.builder httpclient = new okhttpclient.builder(); private static retrofit.builder builder = new retrofit.builder() .baseurl(api_base_url) .addconverterfactory(gsonconverterfactory.create()); public static <s> s createservice(class<s> serviceclass) { retrofit retrofit = builder.client(httpclient.build()).build(); return retrofit.create(serviceclass); } } public interface filedownloadservice { @streaming @get call<responsebody> downloadfilewithdynamicurlsync(@url string fileurl); }
i started downloading task in new thread got this:
android.os.networkonmainthreadexception
if choose download image of 3kb,the program works fine.if add following code:
strictmode.threadpolicy policy = new strictmode.threadpolicy.builder().permitall().build(); strictmode.setthreadpolicy(policy);
the downloading proceed while , stop information:
strictmode policy violation; ~duration=1342 ms: android.os.strictmode$strictmodediskreadviolation: policy=23 violation=2
here's stacktrace:
process: com.testapp.yiyuanguo.apkinstall, pid: 25788 android.os.networkonmainthreadexception @ android.os.strictmode$androidblockguardpolicy.onnetwork(strictmode.java:1147) @ libcore.io.blockguardos.recvfrom(blockguardos.java:249) @ libcore.io.iobridge.recvfrom(iobridge.java:553) @ java.net.plainsocketimpl.read(plainsocketimpl.java:485) @ java.net.plainsocketimpl.access$000(plainsocketimpl.java:37) @ java.net.plainsocketimpl$plainsocketinputstream.read(plainsocketimpl.java:237) @ okio.okio$2.read(okio.java:139) @ okio.asynctimeout$2.read(asynctimeout.java:211) @ okio.realbufferedsource.read(realbufferedsource.java:50) @ okhttp3.internal.http.http1xstream$fixedlengthsource.read(http1xstream.java:381) @ okhttp3.internal.util.skipall(util.java:178) @ okhttp3.internal.util.discard(util.java:160) @ okhttp3.internal.http.http1xstream$fixedlengthsource.close(http1xstream.java:397) @ okio.realbufferedsource.close(realbufferedsource.java:396) @ okio.forwardingsource.close(forwardingsource.java:43) @ okio.realbufferedsource.close(realbufferedsource.java:396) @ okio.realbufferedsource$1.close(realbufferedsource.java:384) @ com.testapp.apkinstall.mainactivity.writeresponsebodytodisk(mainactivity.java:87) @ com.testapp.apkinstall.mainactivity.access$000(mainactivity.java:24) @ com.testapp.apkinstall.mainactivity$1$1.onresponse(mainactivity.java:42) @ retrofit2.executorcalladapterfactory$executorcallbackcall$1$1.run(executorcalladapterfactory.java:68) @ android.os.handler.handlecallback(handler.java:739) @ android.os.handler.dispatchmessage(handler.java:95) @ android.os.looper.loop(looper.java:135) @ android.app.activitythread.main(activitythread.java:5254) @ java.lang.reflect.method.invoke(native method) @ java.lang.reflect.method.invoke(method.java:372) @ com.android.internal.os.zygoteinit$methodandargscaller.run(zygoteinit.java:898) @ com.android.internal.os.zygoteinit.main(zygoteinit.java:693)
onresponse
runs on ui thread
, , bytestream()
accesses underlaying network connection and, exception states, can't it. @epicpandaforce
points out, since using own thread, don't need call enqueue
, can call directly execute()
, blocking call returns response<t>
:
response<responsebody> response = call.execute(); if (response.issuccessful()) { writeresponsebodytodisk(response.body()); }
in case runs on context of thread, , not on ui thread. thread allowed access bytestream()
, , won't experience networkonmainthreadexception
Comments
Post a Comment