
上篇文章: java HttpURLConnection实现简单的网络请求用java实现了简单的网络请求。我们看看在Android的主线程上做网络请求会发生什么本文目录代码测试下异常是在哪个类抛出的完整调用链HttpsURLConnectionImpl在哪里初始化的HttpsURLConnectionImpl的connect()方法里面做了什么代码测试下importandroidx.appcompat.app.AppCompatActivity;importandroid.os.Bundle;importjava.io.ByteArrayOutputStream;importjava.io.InputStream;importjava.net.HttpURLConnection;importjava.net.URL;publicclassMainActivityextendsAppCompatActivity{OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getTextFromHttp();}privatevoidgetTextFromHttp(){try{// 根据地址创建URL对象(网络访问的url)URLurlnewURL(https://publicobject.com/helloworld.txt);HttpURLConnectionurlConnection(HttpURLConnection)url.openConnection();urlConnection.setReadTimeout(5000);urlConnection.setConnectTimeout(5000);urlConnection.connect();if(urlConnection.getResponseCode()200){InputStreamisurlConnection.getInputStream();ByteArrayOutputStreamosnewByteArrayOutputStream();intlen0;bytebuffer[]newbyte[1024];// 按照缓冲区的大小循环读取while((lenis.read(buffer))!-1){// 根据读取的长度写入到os对象中os.write(buffer,0,len);}is.close();// os.close(); //无需关闭urlConnection.disconnect();StringresultnewString(os.toByteArray());System.out.println(result);}else{System.out.println(------------------连接失败-----------------);}}catch(Exceptione){e.printStackTrace();}}}运行下报错了W/System.err: android.os.NetworkOnMainThreadException W/System.err: at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1303) W/System.err: at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:86) W/System.err: at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:74) W/System.err: at java.net.InetAddress.getAllByName(InetAddress.java:752) W/System.err: at com.android.okhttp.internal.Network$1.resolveInetAddresses(Network.java:29) W/System.err: at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:187) W/System.err: at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:156) W/System.err: at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:98) W/System.err: at com.android.okhttp.internal.http.HttpEngine.createNextConnection(HttpEngine.java:345) W/System.err: at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:328) W/System.err: at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:246) W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:457) W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:126) W/System.err: at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:89) W/System.err: at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java) W/System.err: at com.exp.cpdemo.MainActivity.getTextFromHttp(MainActivity.java:41) W/System.err: at com.exp.cpdemo.MainActivity.onCreate(MainActivity.java:31) W/System.err: at android.app.Activity.performCreate(Activity.java:6760) W/System.err: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) W/System.err: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2619) W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2727) W/System.err: at android.app.ActivityThread.-wrap12(ActivityThread.java) W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1478) W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102) W/System.err: at android.os.Looper.loop(Looper.java:154) W/System.err: at android.app.ActivityThread.main(ActivityThread.java:6121) W/System.err: at java.lang.reflect.Method.invoke(Native Method) W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889) W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)异常是在哪个类抛出的/frameworks/base/core/java/android/os/StrictMode.javapublicfinalclassStrictMode{......privatestaticclassAndroidBlockGuardPolicyimplementsBlockGuard.Policy{privateintmPolicyMask;publicAndroidBlockGuardPolicy(finalintpolicyMask){mPolicyMaskpolicyMask;}......publicvoidonNetwork(){if((mPolicyMaskDETECT_NETWORK)0){return;}if((mPolicyMaskPENALTY_DEATH_ON_NETWORK)!0){//在这里抛出了异常thrownewNetworkOnMainThreadException();}......}......}......}接着看谁调用了onNetwork()?libcore/luni/src/main/java/java/net/Inet6AddressImpl.javaprivatestaticInetAddress[]lookupHostByName(Stringhost,intnetId)throwsUnknownHostException{BlockGuard.getThreadPolicy().onNetwork();...}看看BlockGuard.javalibcore/dalvik/src/main/java/dalvik/system/BlockGuard.javapublicstaticPolicygetThreadPolicy(){returnthreadPolicy.get();}完整调用链MainActivity.onCreate() 【主线程执行】 ↓ MainActivity.getTextFromHttp() ↓ HttpsURLConnection.connect() ↓ DelegatingHttpsURLConnection.connect() ↓ HttpURLConnectionImpl.connect() ↓ HttpURLConnectionImpl.execute() ↓ HttpEngine.sendRequest() ↓ HttpEngine.connect() ↓ HttpEngine.createNextConnection() ↓ RouteSelector.next() ↓ RouteSelector.nextProxy() ↓ RouteSelector.resetNextInetSocketAddress() // 触发DNS解析 ↓ Network.resolveInetAddresses() ↓ InetAddress.getAllByName() ↓ Inet6AddressImpl.lookupAllHostAddr() ↓ Inet6AddressImpl.lookupHostByName() // 86行BlockGuard.onNetwork() ↓ StrictMode.AndroidBlockGuardPolicy.onNetwork() ↓ 抛出 NetworkOnMainThreadException 程序终止HttpsURLConnectionImpl在哪里初始化的W/System.err: at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java) W/System.err: at com.exp.cpdemo.MainActivity.getTextFromHttp(MainActivity.java:41) W/System.err: at com.exp.cpdemo.MainActivity.onCreate(MainActivity.java:31)从日志中可以看到urlConnection.connect();执行后就跳到了HttpsURLConnectionImpl.connect()方法。HttpsURLConnectionImpl是什么为什么会跳到HttpsURLConnectionImpl里面URLurlnewURL(https://publicobject.com/helloworld.txt);HttpURLConnectionurlConnection(HttpURLConnection)url.openConnection();...urlConnection.connect();HttpURLConnection是一个抽象类并且里面没有connect()方法。/libcore/luni/src/main/java/java/net/HttpURLConnection.javapublicabstractclassHttpURLConnectionextendsURLConnection{......}看下父类URLConnection里面有没有connect()方法。有但是也是抽象方法。那这个connect()方法到底在哪里实现的publicabstractclassURLConnection{...publicabstractvoidconnect()throwsIOException;...}往前面看对象一定是url.openConnection()生成的。我们看看openConnection()方法源码。/libcore/luni/src/main/java/java/net/URL.javapublicfinalclassURLimplementsSerializable{...transientURLStreamHandlerstreamHandler;...publicURLConnectionopenConnection()throwsIOException{returnstreamHandler.openConnection(this);}}streamHandler是 URLStreamHandler 的对象。继续看URLStreamHandler里面的openConnection()方法。/libcore/luni/src/main/java/java/net/URLStreamHandler.javapublicabstractclassURLStreamHandler{...protectedabstractURLConnectionopenConnection(URLu)throwsIOException;...}URLStreamHandler是一个抽象类。那它的实现类是谁streamHandler是URL的成员变量从URL类里面找找streamHandler的初始化。//我们初始化用的是这个构造器publicURL(Stringspec)throwsMalformedURLException{this((URL)null,spec,null);}//这里入参context为null,handler也为nullpublicURL(URLcontext,Stringspec,URLStreamHandlerhandler)throwsMalformedURLException{if(specnull){thrownewMalformedURLException();}if(handler!null){streamHandlerhandler;}specspec.trim();protocolUrlUtils.getSchemePrefix(spec);intschemeSpecificPartStartprotocol!null?(protocol.length()1):0;...if(context!null){...}elseif(protocolnull){thrownewMalformedURLException(Protocol not found: spec);}if(streamHandlernull){//这里是streamHandler被赋值的地方setupStreamHandler();if(streamHandlernull){thrownewMalformedURLException(Unknown protocol: protocol);}}...}voidsetupStreamHandler(){...// Fall back to a built-in stream handler if the user didnt supply oneif(protocol.equals(file)){streamHandlernewFileHandler();}elseif(protocol.equals(ftp)){streamHandlernewFtpHandler();}elseif(protocol.equals(http)){try{Stringnamecom.android.okhttp.HttpHandler;streamHandler(URLStreamHandler)Class.forName(name).newInstance();}catch(Exceptione){thrownewAssertionError(e);}}elseif(protocol.equals(https)){//从这里可以看到这个streamHandler是HttpsHandlertry{Stringnamecom.android.okhttp.HttpsHandler;streamHandler(URLStreamHandler)Class.forName(name).newInstance();}catch(Exceptione){thrownewAssertionError(e);}}elseif(protocol.equals(jar)){streamHandlernewJarHandler();}if(streamHandler!null){streamHandlers.put(protocol,streamHandler);}}原来streamHandler是HttpsHandler的对象。继续看HttpsHandler的openConnection()方法。/external/okhttp/android/main/java/com/squareup/okhttp/HttpsHandler.javapublicfinalclassHttpsHandlerextendsHttpHandler{......}HttpsHandler 里面没有openConnection()方法接着找他的父类HttpHandler。publicclassHttpHandlerextendsURLStreamHandler{......OverrideprotectedURLConnectionopenConnection(URLurl)throwsIOException{returnnewOkUrlFactory(null/* proxy */).open(url);}...protectedOkUrlFactorynewOkUrlFactory(Proxyproxy){OkUrlFactoryokUrlFactorycreateHttpOkUrlFactory(proxy);// For HttpURLConnections created through java.net.URL Android uses a connection pool that// is aware when the default network changes so that pooled connections are not re-used when// the default network changes.okUrlFactory.client().setConnectionPool(configAwareConnectionPool.get());returnokUrlFactory;}newOkUrlFactory()方法返回了OkUrlFactory对象。我们看OkUrlFactory的open()方法。/external/okhttp/okhttp-urlconnection/src/main/java/com/squareup/okhttp/OkUrlFactory.javapublicfinalclassOkUrlFactoryimplementsURLStreamHandlerFactory,Cloneable{...publicHttpURLConnectionopen(URLurl){returnopen(url,client.getProxy());}HttpURLConnectionopen(URLurl,Proxyproxy){Stringprotocolurl.getProtocol();OkHttpClientcopyclient.copyWithDefaults();copy.setProxy(proxy);if(protocol.equals(http))returnnewHttpURLConnectionImpl(url,copy);if(protocol.equals(https))returnnewHttpsURLConnectionImpl(url,copy);thrownewIllegalArgumentException(Unexpected protocol: protocol);}...}终于我们看到了HttpURLConnection在我们程序里的实现类HttpsURLConnectionImpl。总结下URLConnection是抽象类里面定义了抽象方法connect()。HttpURLConnection也是抽象类虽然继承了URLConnection但是并没有实现connect()方法。URLConnection有三个子类它们都是抽象类。HttpURLConnectionHttpsURLConnectionJarURLConnection。HttpsURLConnectionImpl的connect()方法里面做了什么HttpsURLConnectionImpl中没有connect方法去父类DelegatingHttpsURLConnection中看看。/external/okhttp/okhttp-urlconnection/src/main/java/com/squareup/okhttp/internal/huc/HttpsURLConnectionImpl.javapublicfinalclassHttpsURLConnectionImplextendsDelegatingHttpsURLConnection{...//这个构造器正是OkUrlFactory中使用的publicHttpsURLConnectionImpl(URLurl,OkHttpClientclient){//注意这里传递的是HttpURLConnectionImpl//不是HttpsURLConnectionImplthis(newHttpURLConnectionImpl(url,client));}publicHttpsURLConnectionImpl(HttpURLConnectionImpldelegate){super(delegate);//这里调用了父类的构造器this.delegatedelegate;}}/external/okhttp/okhttp-urlconnection/src/main/java/com/squareup/okhttp/internal/huc/DelegatingHttpsURLConnection.javaabstractclassDelegatingHttpsURLConnectionextendsHttpsURLConnection{privatefinalHttpURLConnectiondelegate;publicDelegatingHttpsURLConnection(HttpURLConnectiondelegate){super(delegate.getURL());this.delegatedelegate;}......Overridepublicvoidconnect()throwsIOException{connectedtrue;delegate.connect();}......}注意这里的delegate是HttpURLConnection对象不是HttpsURLConnection对象。上面已经分析了HttpURLConnection没有connect()方法。那这个delegate又是哪个类的对象注意到delegate有private final修饰所以只可能在DelegatingHttpsURLConnection类中赋值结合上面源码就是在构造器中赋值的。看上面HttpsURLConnectionImpl的源码可知这个delegate其实是HttpURLConnectionImpl对象。所以delegate.connect();最终调用的是HttpURLConnectionImpl的connect()方法。真的能绕啊/external/okhttp/okhttp-urlconnection/src/main/java/com/squareup/okhttp/internal/huc/HttpURLConnectionImpl.javapublicclassHttpURLConnectionImplextendsHttpURLConnection{...Overridepublicfinalvoidconnect()throwsIOException{initHttpEngine();booleansuccess;do{successexecute(false);}while(!success);}...}后面就是execute()方法了有时间再分析。可参考HttpURLConnection源码解读