Android Question BLE2 java.lang.RuntimeException: Error writing data to:

wes58

Active Member
Licensed User
Longtime User
I have the following error due to the problem with writing data to BLE device - due to the issue with the BLE device for example:
B4X:
retries: 4
retries: 3
retries: 2
retries: 1
java.lang.RuntimeException: Error writing data to: 00001f1f-0000-1000-8000-00805f9b34fb
    at anywheresoftware.b4a.objects.BleManager2.WriteData(BleManager2.java:426)
    at b4a.ble3.starter._writedata(starter.java:829)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:213)
    at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:1082)
    at anywheresoftware.b4a.keywords.Common.CallSubNew2(Common.java:1037)
    at b4a.ble3.main._bgetname_click(main.java:1356)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:213)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:197)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:193)

After 4 retries application crasshes.
I had a look at the BLE2 code:
Java:
    /**
     * Writes the data to the specified characteristic.
     */
    public void WriteData(String Service, String Characteristic, byte[] Data) throws InterruptedException {
        BluetoothGattCharacteristic chr = getChar(getService(Service), Characteristic);
        chr.setValue(Data);
        int retries = 5;
        while (true) {
            if (!gatt.writeCharacteristic(chr)) {
                if (--retries <= 0)
                    throw new RuntimeException("Error writing data to: " + Characteristic);
            }
            else
                break;
            BA.Log("retries: " + retries);
            Thread.sleep(150 * (5 - retries));
        }
    }
I thought that it would be better way of handling of writing error than throwing RuntimeException and crashing the app after number of retries!

Edit:
I noticed that there is an event raised in callback function onCharacteristicWrite(), with the status of the write process:
Java:
        public void onCharacteristicWrite(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic, int status) {
            if (characteristic == null || characteristic.getUuid() == null)
                return;
            ba.raiseEventFromDifferentThread(BleManager2.this, null, 0, eventName + "_writecomplete", false,
                    new Object[] {characteristic.getUuid().toString(), status});
        }
So do we need to have a RuntimeException?
 
Last edited:

wes58

Active Member
Licensed User
Longtime User
Catch the error with Try / Catch.
Sorry, I am a beginner with Java, but I can't understand why would you want to use Try/Catch? You know what the issue is - you retried 5 times and can't write to the device - so why not raise an event and notify the user about "writing error to ble device". Application can continue to run.

The same thing I noticed in your connect() function.
Java:
    /**
     * Similar to Connect. Allows you to disable auto connection.
     */
    public void Connect2(String DeviceId, boolean AutoConnect) {
        charsToReadQueue.clear();
        BluetoothDevice bd = this.devices.get(DeviceId);
        if (bd == null) 
            throw new RuntimeException("MacAddress not found. Make sure to call Scan before trying to connect.")
        else {
            bd.connectGatt(BA.applicationContext, AutoConnect, new GattCallback());
        }
    }
You have "throw new RuntimeException("MacAddress not found. Make sure to call Scan before trying to connect.")".
Why not handling this error and notify the user that he has to scan before trying to connect, instead of crashing the app?
An easy way to do it, would be, to return boolean from this function , and return FALSE if bd=null, which would mean that mac address was not found.
That's only my suggestion, you are a Java expert, so you know better what to do.
 
Upvote 0

wes58

Active Member
Licensed User
Longtime User
It has nothing to do with Java.

There are many cases where a failed operation throws exceptions.
It was only my understanding of exceptions.
And here is what others think about RuntimeExceptions:
How to handle the Runtime Exception in Java?

The Runtime Exception
is the parent class in all exceptions of the Java programming language that are expected to crash or break down the program or application when they occur. Unlike exceptions that are not considered as Runtime Exceptions, Runtime Exceptions are never checked.

The Runtime Exception usually shows the programmer's error, rather than the condition a program is expected to deal with. Runtime Exceptions are also used when a condition that can't happen. It should be noted that when a program is running out of memory, a program error is thrown instead of showing it as a Runtime Exception.
In the examples I mentioned, it is not a programmer's error. And the program could deal with this error!

Or another one:

Unchecked Exceptions — The Controversy​

Because the Java programming language does not require methods to catch or to specify unchecked exceptions (RuntimeException, Error, and their subclasses), programmers may be tempted to write code that throws only unchecked exceptions or to make all their exception subclasses inherit from RuntimeException. Both of these shortcuts allow programmers to write code without bothering with compiler errors and without bothering to specify or to catch any exceptions. Although this may seem convenient to the programmer, it sidesteps the intent of the catch or specify requirement and can cause problems for others using your classes.
Why did the designers decide to force a method to specify all uncaught checked exceptions that can be thrown within its scope? Any Exception that can be thrown by a method is part of the method's public programming interface. Those who call a method must know about the exceptions that a method can throw so that they can decide what to do about them. These exceptions are as much a part of that method's programming interface as its parameters and return value.
The next question might be: "If it's so good to document a method's API, including the exceptions it can throw, why not specify runtime exceptions too?" Runtime exceptions represent problems that are the result of a programming problem, and as such, the API client code cannot reasonably be expected to recover from them or to handle them in any way. Such problems include arithmetic exceptions, such as dividing by zero; pointer exceptions, such as trying to access an object through a null reference; and indexing exceptions, such as attempting to access an array element through an index that is too large or too small.
Runtime exceptions can occur anywhere in a program, and in a typical one they can be very numerous. Having to add runtime exceptions in every method declaration would reduce a program's clarity. Thus, the compiler does not require that you catch or specify runtime exceptions (although you can).
One case where it is common practice to throw a RuntimeException is when the user calls a method incorrectly. For example, a method can check if one of its arguments is incorrectly null. If an argument is null, the method might throw a NullPointerException, which is an unchecked exception.
Generally speaking, do not throw a RuntimeException or create a subclass of RuntimeException simply because you don't want to be bothered with specifying the exceptions your methods can throw.
Here's the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.
That's why I thought, that in the examples I mentioned there was no need of throwing RuntimeExceptions.
Obviously, you have a different opinion about it, and that's OK.
 
Upvote 0
Top