第一次尝试 OkHttp 作为客户端时崩溃

Crashing when first time try OkHttp as a client

我有一些项目,实时发送蓝牙低功耗的 RSSI 和 MAC。我想尝试使用 http 协议,我找到了 OkHttp 库。但是当我 运行 使用 OkHttp 时,我的软件崩溃了。

我的错误

2022-04-02 10:22:56.681 20521-20521/com.example.android_http D/Logger: State Check
2022-04-02 10:22:57.146 20521-20521/com.example.android_http D/Logger: Recive data 6C:70:3C:0A:99:43
2022-04-02 10:22:57.217 20521-20521/com.example.android_http D/AndroidRuntime: Shutting down VM
2022-04-02 10:22:57.220 20521-20521/com.example.android_http E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.android_http, PID: 20521
    Theme: themes:{}
    java.lang.RuntimeException: Error receiving broadcast Intent { act=android.bluetooth.device.action.FOUND flg=0x10 (has extras) } in com.example.android_http.MainActivity@6febfe0
        at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:892)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5456)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
     Caused by: android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1273)
        at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:110)
        at libcore.io.IoBridge.connectErrno(IoBridge.java:154)
        at libcore.io.IoBridge.connect(IoBridge.java:122)
        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:183)
        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:452)
        at java.net.Socket.connect(Socket.java:884)
        at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.kt:63)
        at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:295)
        at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:207)
        at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
        at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
        at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
        at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
        at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
        at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
        at com.example.android_http.postActivity.post(postActivity.java:22)
        at com.example.android_http.MainActivity.onReceive(MainActivity.java:118)
        at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:882)
        at android.os.Handler.handleCallback(Handler.java:739) 
        at android.os.Handler.dispatchMessage(Handler.java:95) 
        at android.os.Looper.loop(Looper.java:148) 
        at android.app.ActivityThread.main(ActivityThread.java:5456) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

我确定是 OkHttp 导致应用程序崩溃。因为在使用 OkHttp 之前应用程序很好。

这是我的mainActivity.java

package com.example.android_http;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.io.IOException;


public class MainActivity extends AppCompatActivity {

    private Button btnTurn;
    private boolean state = false;
    private BluetoothAdapter bluetoothAdapter;
    public static final int REQUEST_ACCESS_COARSE_LOCATION = 1;
    public String data;
    postActivity ClientHttp = new postActivity();

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

        btnTurn = findViewById(R.id.btnTurn);
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                stateCheck();
                Log.d("Logger", "State Check");
                handler.postDelayed(this, 1000);
            }
        }, 1000);

        btnTurn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(!state){
                    btnTurn.setText("Turn Off");
                    state = true;
                }else{
                    btnTurn.setText("Turn On");
                    state = false;
                }
            }
        });
    }

    public void stateCheck(){
        if (state){
            if (bluetoothAdapter!=null & bluetoothAdapter.isEnabled()) {
                if(checkCoarsePermission()){
                    Log.d("Logger", "Discover");
                    bluetoothAdapter.startDiscovery();
                }
            }
        }
    }

    private boolean checkCoarsePermission(){
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_COARSE_LOCATION},
                    REQUEST_ACCESS_COARSE_LOCATION);
            return false;
        }else {
            return true;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(devicesFoundReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
        registerReceiver(devicesFoundReceiver, new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED));
        registerReceiver(devicesFoundReceiver, new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED));

    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(devicesFoundReceiver);
    }

    private final BroadcastReceiver devicesFoundReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action= intent.getAction();

            if(BluetoothDevice.ACTION_FOUND.equals(action)){
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                int  rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI,Short.MIN_VALUE);
                String RSSI = String.valueOf(rssi);
                Toast.makeText(context.getApplicationContext(),"rssi "+RSSI+" "+device.getAddress(),Toast.LENGTH_SHORT).show();
                Log.d("Logger", "Recive data "+device.getAddress());
                data = "RSSI: "+RSSI+" MAC: "+device.getAddress();
                String data_json = "{'rssi':'"+RSSI+"','MAC':'"+device.getAddress()+"'";
                try{
                    String response = ClientHttp.post("http://192.168.6.56:3000/clicked",data_json);
                    Log.d("Logger",response);
                }catch (IOException e){
                    Log.e("Logger","Error Function to send");
                }

//                try{
//                    //GetText(mUrl,data);
//                }catch (IOException e){
//                    Log.e("Logger","Error Function to send");
//                }

            }else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
            }else if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
            }
        }
    };

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        switch (requestCode){
            case REQUEST_ACCESS_COARSE_LOCATION:
                if(grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    Toast.makeText(this,"ALLOWED", Toast.LENGTH_SHORT).show();
                }else {
                    Toast.makeText(this,"Forbidden",Toast.LENGTH_SHORT).show();
                } break;
        }
    }

}

这是我的postActivity.java

package com.example.android_http;

import java.io.IOException;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class postActivity {
    public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");

    final OkHttpClient client = new OkHttpClient();

    String post(String url, String json) throws IOException {
        RequestBody body = RequestBody.create(json, JSON);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        }
    }
}

我的gradle

dependencies {

    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

    implementation("com.squareup.okhttp3:okhttp:4.9.3")
    implementation("com.squareup.okhttp3:okhttp")
}

为了更清楚的解释,我在 Android Studio 中使用 JAVA 和 Android 6.0 的 API 进行了编程。

我的问题很简单,如何解决这个问题?为什么会崩溃?请不要关闭我的问题!!!我只是个初学者!!!这个问题在其他 post 中不存在,我尝试用我的原始代码实现另一个 post。但仍然失败。

谢谢。

错误是在主线程(a.k.a.UI线程)上执行网络请求引起的。通常,主线程禁止线程阻塞操作(如文件读取、网络请求)。这样做是为了避免 App Not responding 错误。

在你的 mainActivity.java 中,因为 BroadcastReceiver#onReceive 是在主线程上执行的。 (参考:)。在这个 onReceive 函数中,您正在尝试发出网络请求。

只是,使用处理程序和 post 对后台线程(或任何其他线程)的网络调用,这将解决您的问题。