为什么 Android 阻止了我的 OkHttp 请求

Why Android is blocking my OkHttp Request

我试图用 OkHttp 调用我的 API 但是 android 不希望我这样做! 我读到我需要让我的 class extends AsyncTask 但它不起作用 也许我只是不知道如何使其异步但这是我尝试使其异步之前的代码 你能帮帮我吗?

这是我的 OkHttpHelper class 包裹 com.example.mygostyle

import android.content.Context
import android.os.AsyncTask
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONObject
import java.io.IOException


class OkHttpHelper {

    var client = OkHttpClient()
    var token : String
    init{
        token = ""
    }

    fun login(un: String, pwd: String, context: Context) : Boolean{

        val urlBuilder = HttpUrl.Builder()
            .scheme("https")
            .host("dev.api.gostyle.ovh")
            .addPathSegment("api")
            .addPathSegment("user")
            .addPathSegment("auth")
            .addQueryParameter("username",un)
            .addQueryParameter("password",pwd)
            .build()

        var request = Request.Builder()
            .url(urlBuilder)
            .build()

        client.newCall(request).execute().use { response ->
            if (!response.isSuccessful) throw IOException("Unexpected code $response")
            val responseData = response.body?.string()
            val json = JSONObject(responseData)
            val owner = json.getString("token")
            if(response.code == 200) {
                saveToken(context, owner)
                return true
            }
            return false
        }
    }

    fun saveToken(context: Context, token : String){
        val sharedPreference = SharedPreference(context)
        sharedPreference.save("MyGoStyleToken",token)

    }

}

这是我的登录名Activity 包裹 com.example.mygostyle

import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.content.Intent
import android.view.Window
import android.view.WindowManager
import android.widget.EditText


class LoginActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        this.requestWindowFeature(Window.FEATURE_NO_TITLE)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)

        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        this.setContentView(R.layout.activity_login);

        val loginbtn = findViewById<Button>(R.id.loginbtn)

        loginbtn.setOnClickListener(){
            login(this)
        }
    }

    fun login(context: Context){
        var okHttpHelper = OkHttpHelper()
        val uninput = findViewById<EditText>(R.id.username_input).text.toString()
        val pwdinput = findViewById<EditText>(R.id.password_input).text.toString()
        if(okHttpHelper.login(uninput,pwdinput,context)) {
            val gameActivity = Intent(this@LoginActivity, MyPromosActivity::class.java)
            startActivity(gameActivity)
        }

    }


}

错误日志:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.mygostyle, PID: 20075
    android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1450)
        at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:102)
        at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:90)
        at java.net.InetAddress.getAllByName(InetAddress.java:787)
        at okhttp3.Dns$Companion$SYSTEM.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 com.example.mygostyle.OkHttpHelper.login(OkHttpHelper.kt:36)
        at com.example.mygostyle.LoginActivity.login(LoginActivity.kt:34)
        at com.example.mygostyle.LoginActivity$onCreate.onClick(LoginActivity.kt:26)
        at android.view.View.performClick(View.java:6294)
        at android.view.View$PerformClick.run(View.java:24770)
        at android.os.Handler.handleCallback(Handler.java:790)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

如前所述,您无法在 MainThread 上进行网络请求。因此,一种方法是 AsyncTask as:

class LoginActivity : AppCompatActivity() {

    fun login(context: Context){

        AsyncTask.execute {

            var okHttpHelper = OkHttpHelper()
            val uninput = findViewById<EditText>(R.id.username_input).text.toString()
            val pwdinput = findViewById<EditText>(R.id.password_input).text.toString()
            if(okHttpHelper.login(uninput,pwdinput,context)) {
                val gameActivity = Intent(this@LoginActivity, MyPromosActivity::class.java)
                startActivity(gameActivity)
            }
        }

    }

}

如错误所述,您正在主线程上进行网络调用,这是被禁止的,因为进行网络调用是一项非常耗时的操作。

execute 函数以同步方式发出 API 请求,而 enqueue 函数以异步方式发出请求,正如您可能知道的那样,当您想要进行异步调用时,您不能 return 函数中的东西因为代码不再按顺序工作,所以你必须制作一个类似于回调的接口。

interface MyCallback {
    fun onResult(result: bool)
}


fun login(un: String, pwd: String, context: Context, myCallback: MyCallback) {

        val urlBuilder = HttpUrl.Builder()
            .scheme("https")
            .host("dev.api.gostyle.ovh")
            .addPathSegment("api")
            .addPathSegment("user")
            .addPathSegment("auth")
            .addQueryParameter("username",un)
            .addQueryParameter("password",pwd)
            .build()

        var request = Request.Builder()
            .url(urlBuilder)
            .build()

        client.newCall(request).enqueue(object: Callback {
          override public fun onFailure(call: Call, e: IOException) {
             throw IOException("Unexpected code $response")
          }
          override public fun onResponse(call: Call, response: Response) {
             if (!response.isSuccessful) throw IOException("Unexpected code $response")
             val responseData = response.body?.string()
             val json = JSONObject(responseData)
             val owner = json.getString("token")
             if(response.code == 200) {
                  saveToken(context, owner)
                  myCallback,onResult(true)
             }
             myCallback,onResult(false)
         }
       })
    }

所以登录函数不会有return类型,可以这样调用这个函数

class LoginActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        this.requestWindowFeature(Window.FEATURE_NO_TITLE)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)

        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        this.setContentView(R.layout.activity_login);

        val loginbtn = findViewById<Button>(R.id.loginbtn)

        loginbtn.setOnClickListener(){
            login(this, object : MyCallback {
               public override fun onResult(result: Boolean) {
                  // Do something with the result returned
               }
        })
    }

    fun login(context: Context, callback, MyCallback){
        var okHttpHelper = OkHttpHelper()
        val uninput = findViewById<EditText>(R.id.username_input).text.toString()
        val pwdinput = findViewById<EditText>(R.id.password_input).text.toString()
        if(okHttpHelper.login(uninput,pwdinput,context, callback)) {
            val gameActivity = Intent(this@LoginActivity, MyPromosActivity::class.java)
            startActivity(gameActivity)
        }

    }


}