1. 程式人生 > 實用技巧 >okHttpClient發起網路請求失敗

okHttpClient發起網路請求失敗

Android中傳送HTTP請求,報錯如下

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: cn.iyikong.managementterminal, PID: 4447
    android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1571)
        at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:115)
        at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:103)
        at java.net.InetAddress.getAllByName(InetAddress.java:1152)
        at okhttp3.Dns$Companion$SYSTEM$1.lookup(Dns.kt:48)
        at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.kt:160)
        at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.kt:125)
        at okhttp3.internal.connection.RouteSelector.next(RouteSelector.kt:71)
        at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:199)
        at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:109)
        at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:77)
        at okhttp3.internal.connection.Transmitter.newExchange$okhttp(Transmitter.kt:162)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:35)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:82)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:84)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:71)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.kt:184)
        at okhttp3.RealCall.execute(RealCall.kt:66)
        at cn.iyikong.managementterminal.service.WebService.getPullAndPushNumber(WebService.java:606)
        at cn.iyikong.managementterminal.VideoActivity.onMediaOnPreparedNotify(VideoActivity.java:1213)
        at cn.iyikong.managementterminal.handler.MediaHandler.handleMessage(MediaHandler.java:48)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:224)
        at android.app.ActivityThread.main(ActivityThread.java:7562)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
E/CrashReport: Java Crash Happen cause by main(2)

在Activity.java中呼叫HTTP網路請求時,怎麼都走不過去

/**
     * 獲取視訊拉流數量
     * @author ct
     * @return String
     */
    public static Integer getPullAndPushNumber(String imei) {
        Integer pullNumber = 0;
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .url(Constant.GET_EQUIP_PULL_Number)
                .build();
        try (Response response = okHttpClient.newCall(request).execute()) { //每次到這裡都會報錯
            if(null != response.body()){
                //1.獲取請求資料轉換成map集合
                Map map = JSON.parseObject(response.body().string(),Map.class);
                //2.獲得詳細列表物件集合轉換成map集合
                Map map2 = JSON.parseObject(map.get("bridges").toString());
                //3.map迴圈key值
                for (Object obj : map2.keySet()){
                    //4.當key值與IMEI相等時,獲取拉流裝置數量
                    if(obj.equals(imei)){
                        //5.拉流裝置數量等於陣列字串中逗號的數量
                        pullNumber = map2.get(obj).toString().split(",").length;
                    }
                }
            }
        } catch (IOException e){
            e.printStackTrace();
        }
        return pullNumber;
    }

翻了翻資料,發現原因是:不允許在主執行緒中進行網路訪問
下面是我找到的幾種解決方法,我用的第一個

一、直接在請求的Activity中的onCreate方法中新增如下程式碼:

Activity.java

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
        .detectDiskReads().detectDiskWrites().detectNetwork()

        .penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
        .detectLeakedSqlLiteObjects().detectLeakedClosableObjects()
        .penaltyLog().penaltyDeath().build());

發起請求

/**
     * 獲取視訊拉流數量
     * @author ct
     * @return Integer
     */
    public static Integer getPullAndPushNumber(String imei) {
        Integer pullNumber = 0;
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .url(Constant.GET_EQUIP_PULL_Number)
                .build();
        try (Response response = okHttpClient.newCall(request).execute()) {
            if(null != response.body()){
                //1.獲取請求資料轉換成map集合
                Map map = JSON.parseObject(response.body().string(),Map.class);
                //2.獲得詳細列表物件集合轉換成map集合
                Map map2 = JSON.parseObject(map.get("bridges").toString());
                //3.map迴圈key值
                for (Object obj : map2.keySet()){
                    //4.當key值與IMEI相等時,獲取拉流裝置數量
                    if(obj.equals(imei)){
                        //5.拉流裝置數量等於陣列字串中逗號的數量
                        pullNumber = map2.get(obj).toString().split(",").length;
                    }
                }
            }
        } catch (IOException e){
            e.printStackTrace();
        }
        return pullNumber;
    }

二、建立子執行緒,把網路請求放到子執行緒裡執行,這種沒試過,這種好像沒有返回值,麼法把查到的資料顯示在頁面上,不太懂

new Thread(){  
   @Override  
   public void run()  
   {  
   //把網路訪問的程式碼放在這裡     
  }  
}.start();

三、使用非同步請求

/**
     * 獲取視訊拉流數量
     * @author ct
     * @return Integer
     */
    public static Integer getPullAndPushNumber(String imei) {
        OkHttpClient okHttpClient = new OkHttpClient();
        HttpUrl.Builder urlBuilder = HttpUrl.parse(Constant.GET_EQUIP_PULL_Number)
                .newBuilder();
        Request request = new Request.Builder()
                .url(urlBuilder.build())
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                LogUtil.d("getPullAndPushNumber", "onFailure: ");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //1.字串轉JSON物件
                Map map = JSON.parseObject(response.body().string(),Map.class);
                //4.獲取詳細引數字串
                for (Object obj : map.keySet()){
                    LogUtil.d("getPullAndPushNumber", "key為:"+obj+"值為:"+map.get(obj));
                }
                Map map2 = JSON.parseObject(map.get("bridges").toString());
                for (Object obj : map2.keySet()){
                    LogUtil.d("getPullAndPushNumber-----2", "key為:"+obj+"值為:"+map2.get(obj));
                    if(obj.equals(imei)){
                        System.out.println(map2.get(obj).toString().split(",").length);
                    }
                }
            }
        });
        return 0;
    }

總結:
用了第一個與第三個方法,問題解決了;至於為啥解決了就不太明白了,大概是主執行緒中不允許使用網路請求
第三個方法沒有返回值,適合進行增刪改操作,查詢的話還是用第一個吧,以後再學學還有沒有其他方法