Java Question Passing array back to Java in argument

Discussion in 'Libraries developers questions' started by divinglog, Aug 29, 2019.

  1. divinglog

    divinglog Member Licensed User

    Hello

    I raise an event from Java with a byte array as argument:

    Code:
    private int Read(long userdata, byte[] data, int size, Object actual) {
            ba.raiseEvent(this, eventName + 
    "_read", userdata, data, size, actual);
            ba.Log(
    "First Byte: " + data[0]);
            
    return 0;
        
    }
    In B4A I want to update the data argument which should be returned to Java. Because I do not know the size of the array before raising the event, the array is not initialized. How can I update the array in B4A without loosing the reference?

    I tried this:

    Code:
    Private Sub LibDC_Read(Userdata As Long, Data() As Byte, Size As Int, Actual As Object) As Int
        
    Dim TempArr() As Byte
       
        
    'Does not work:
        TempArr = File.ReadBytes(Common.LogDir, "File.bin")
        Data = Temparr

        
    'Does not work:
        Dim bc As ByteConverter
        
    Dim Data(TempArr.Length) As Byte
        bc.ArrayCopy(TempArr, 
    0, Data, 0, TempArr.Length)
       
        
    Return 0
    End Sub
    ArrayCopy works only if the array had already the correct size before raising the event and I do not have to redim it. But as I do not know the size before, I can't do that. So how can I pass back a byte array with unknown size in an event argument?

    Thank you!
     
  2. OliverA

    OliverA Expert Licensed User

    raiseEvent is more equivalent to CallSubDelayed then CallSub. Therefore, the execution is

    ba.raiseEvent
    ba.Log
    return 0

    Then
    LibDC_Read

    Therefore, LibDC_Read does not communicate back/has any ties back to the Read method in your java source (as it stands).
     
  3. divinglog

    divinglog Member Licensed User

    As far as I understand it has, because arrays are passed by reference, so it actually communicates back to Java. I've tested it and it works when the array has already the correct size.

    But I think I've found already a workround. The "Size" parameter contains the number of bytes which are requested. So I simply initialize the array with this size and return either the exact number of bytes if available. If less bytes are available, I return the actual number of bytes in the "Actual" argument and deal with that afterwards.
     
  4. OliverA

    OliverA Expert Licensed User

    But as is, you are relying on some weird timing for Java to get the data back. How does Java know that LibDC_Read has been called yet, that it has finished processing? raiseEvent raises an event in the event queue. Currently you have now mechanism in place (at least that you are showing) that ensures the data received in your Java code has been properly processed by the LibDC_Read method.
     
  5. divinglog

    divinglog Member Licensed User

    If I understand this correctly, this works all synchronously, so when ba.raiseEvent returns in Java code, the B4A event code has been processed. The Java "Read" function itself is a callback from JNI via CallIntMethod, so the data in the array from B4A is processed in native C code after the JNI CallIntMethod has returned.

    So it's like this:

    C-Code: CallIntMethod...
    Java Code: Read...
    B4A Code LibDC_Read...
    Java Code
    C-Code
     
  6. OliverA

    OliverA Expert Licensed User

    Looks like you are correct (and I'm wrong). Btw, it also looks like you can have a return value for ba.raiseEvent, thus you could create a new byteArray and return it to your calling Java method and it could then pass it on as required.

    Links:
    https://www.b4x.com/android/forum/threads/raiseevent-or-raiseeventfromdifferentthread.83574/#content
    https://www.b4x.com/android/forum/threads/handle-return-value-with-raisevent.30953/#post-285620
     
    divinglog, DonManfred and Erel like this.
  7. divinglog

    divinglog Member Licensed User

    Yes, I'm already using the return value for a status code. The native library requires actually 3 values to be returned: an int as status code (0 = success) as return value, and the "Data" and "Actual" parameters which are native pointers and are updated in B4A by reference.

    That's the reason why I cannot create a new array in B4A, because this is loosing the reference to the native pointer from C.

    This works all perfectly fine and the data gets through to the C-code. The only problem was the initialization of the array, but the solution I've posted above works just fine. The only downside is that the array might be larger than necessary. Thank you for your help and thoughts!
     
    Last edited: Aug 30, 2019
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice