skip to Main Content

I’m have some project, realtime sending RSSI and MAC of Bluetooth Low Energy. I want try using http protocol, and i found OkHttp library. But when i run with OkHttp, my software crash.

My error

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$3@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$3.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) 

I’m sure it’s OkHttp that crashes the app. Because before using OkHttp the app was fine.

This is my 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;
        }
    }

}

This is my 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();
        }
    }
}

My 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")
}

For a clearer explanation, I did programming using JAVA in Android Studio with API for Android 6.0.

My question is simple, how to fix this problem? and why it crashes? PLEASE DON’T CLOSED MY QUESTIONS!!! I AM JUST A BEGINNER!!! This problem does not exist in other posts and I have tried to implement another post with my origin code. But STILL FAIL.

Thanks.

2

Answers


  1. The error is caused due to execution of network request on main thread (a.k.a. UI thread). In general, thread blocking operations (like file read, network requests) are prohibited on main thread. This is done to avoid App Not responding error.

    In your mainActivity.java, since BroadcastReceiver#onReceive is executed on main thread. (Ref: https://stackoverflow.com/a/5676888/5309486 ). And inside this onReceive function, you are trying to make the network request.

    Just, use handler and post the network call to background thread (or any other thread) and that will fix your issue.

    Login or Signup to reply.
  2. The App will keep crashing until you separate the the network request from the main java thread.

    solution:
    create a class for this request in a separate class file, the class here is both for POST and GET

    public class reques_handler {
    public static String sendRequest(String requestUrl, HashMap<String, String> parameter){
        URL url;
        StringBuilder sb = new StringBuilder();
        try {
            //Initializing Url
            url = new URL(requestUrl);
    
            //Creating an httmlurl connection
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
    
            //Configuring connection properties
            conn.setReadTimeout(15000);
            conn.setConnectTimeout(15000);
            conn.setRequestMethod("POST");
            conn.setDoInput(true);
            conn.setDoOutput(true);
    
            //Creating an output stream
            OutputStream os = conn.getOutputStream();
    
            //Writing parameters to the request
            //We are using a method getPostDataString which is defined below
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
            writer.write(getPostDataString(parameter));
    
            writer.flush();
            writer.close();
            os.close();
            int responseCode = conn.getResponseCode();
    
            if (responseCode == HttpsURLConnection.HTTP_OK) {
    
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                sb = new StringBuilder();
                String response;
                //Reading server response
                while ((response = br.readLine()) != null) {
                    sb.append(response);
                }
            }
    
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }
    public String sendGetRequest(String requestURL) {
        StringBuilder sb = new StringBuilder();
        try {
            URL url = new URL(requestURL);
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
    
            String s;
            while ((s = bufferedReader.readLine()) != null) {
                sb.append(s + "n");
            }
        } catch (Exception e) {
        }
        return sb.toString();
    }
    private static String getPostDataString(HashMap<String, String> params) throws UnsupportedEncodingException {
        StringBuilder result = new StringBuilder();
        boolean first = true;
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (first)
                first = false;
            else
                result.append("&");
    
            result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
            result.append("=");
            result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
        }
    
        return result.toString();
    }
    
    }
    

    at your fragment create this class, this class is responsible of running the network threat in the background to avoid interference with the main thread

    private class PerformNetworkRequestmeter extends AsyncTask<Void, Void, String> {
        String url;
        HashMap<String, String> params;
        PerformNetworkRequestmeter(String url, HashMap<String, String> params) {
            this.url = url;
            this.params = params;
        }
    
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            //view_member__progressBar.setVisibility(View.VISIBLE);
        }
    
    
        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            //view_member__progressBar.setVisibility(View.GONE);
    
            try {
                JSONObject object = new JSONObject(s);
    
    
                detail.setText(object.toString());
                    //populateDescoType(object.getJSONArray("fetchmessage"));
                    Toast.makeText(getActivity(), object.toString(), Toast.LENGTH_SHORT).show();
    
    
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        protected String doInBackground(Void... voids) {
            reques_handler requestHandler = new reques_handler();
    /////// replace the below code with this if your method is POST return requestHandler.sendRequest(url, params);
            return requestHandler.sendGetRequest(url);
    
    
        }
    }
    

    Then in your event handler
    call the class like this

    String UR = "";
    use the commented code to pass parameter if your method is POST but if GET send the URL with it parameter only.
                       /* HashMap check = supportclass.testAPI("62120044771", "KANO","PREPAID","true", getActivity());*/
                        PerformNetworkRequestmeter requestpayWith = new PerformNetworkRequestmeter(UR,check);
                        requestpayWith.execute();
    

    For the record, I got most of this code from stack many years ago. THANKS TO STACK

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search