OKhttp提供的例子不完整

问题描述

我把这段代码放到一个新项目中:

https://raw.githubusercontent.com/square/okhttp/master/samples/guide/src/main/java/okhttp3/guide/GetExample.java

我已将此添加到清单

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

我已经添加了要拉入的 gradle 组件,否则它甚至无法编译,但这段代码绝对没有任何作用。当我将它复制到一个空的应用程序中时,该应用程序崩溃了。

我已尝试将其放入“基本操作”示例中,该示例至少不会崩溃,但代码不会发出 http 请求。

package com.example.hellokitty;

import android.os.Bundle;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import android.view.View;

import android.view.Menu;
import android.view.MenuItem;
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;


public class MainActivity extends AppCompatActivity {

    OkHttpClient client = new OkHttpClient();

    String run(String url) throws IOException {
        Request request = new Request.Builder()
                .url(url)
                .build();

        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        }
    }

    public static void main(String[] args) throws IOException {
        MainActivity example = new MainActivity();
        String response = example.run("http://10.10.0.11/kek");
        System.out.println(response);
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setonClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view,"Replace with your own action",Snackbar.LENGTH_LONG)
                        .setAction("Action",null).show();
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main,menu);
        return true;
    }

    @Override
    public boolean onoptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button,so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onoptionsItemSelected(item);
    }
}

解决方法

我已经试过你的代码了。 它崩溃是因为您在主线程上运行网络操作。你得到 NetworkOnMainThreadException 运行时异常。

为了避免这种情况,您需要更换

try (Response response = client.newCall(request).execute()) {
    return response.body().string();
}

client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(@NotNull Call call,@NotNull IOException e) {
        e.printStackTrace();
    }

    @Override
    public void onResponse(@NotNull Call call,@NotNull Response response) throws IOException {
        String url = response.body().string();
        //your code here
    }
});

整个代码将是:

public class MainActivity extends AppCompatActivity {

    private OkHttpClient client;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        client = new OkHttpClient();
        
        run("http://10.10.0.11/kek");
    }

    private void run(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call,@NotNull IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(@NotNull Call call,@NotNull Response response){
                String url = response.body().toString();
                //your code here
            }
        });
    }
}

从 Android 9(API 级别 28)开始,默认情况下禁用明文支持。

因此,当您拨打 http://10.10.0.11/kek 时,您将收到 java.io.IOException: * 不允许的明文 HTTP 流量

这就是您需要在安全配置中启用明文流量的原因。

在您的 AndroidManifest.xml 中:

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        ...
        android:networkSecurityConfig="@xml/network_security_config"
        ...>
        ...
    </application>
</manifest>

创建文件 res/xml/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true"/>
</network-security-config>