【问题标题】:Context dispatchStatusEventAsync throwing IllegalArgumentException上下文 dispatchStatusEventAsync 抛出 IllegalArgumentException
【发布时间】:2024-05-29 16:30:02
【问题描述】:

我正在为专有蓝牙 LE 设备创建一个与 Android SDK 接口的 ANE。 SDK 已经在纯 Android 项目上进行了测试,并且运行良好。我正在使用 FREContext.dispatchStatusEventAsync 返回有关检测到的每个信标的信息。但是,在 AIR 应用程序运行时查看从 LogCat 返回的日志时,我看到每次找到信标时都会引发 IllegalArgumentException。有趣的是,我可以在其他任何地方使用 dispatchStatusEventAsync 并且它似乎工作正常。

这里是 ANE 的所有相关代码。 (我通过查找/替换掩盖了 SDK 的名称,但代码可以编译,所以如果类或函数的命名有问题,请不要认为这是一个可能的问题。

“DUMMY”语句只是表示它们用于调试。

BecsterExtension.java

public class BecsterExtension implements FREExtension 
{
    public static final String TAG = "BecsterExtension";

    @Override
    public FREContext createContext(String arg0) 
    {
        return new BecsterContext();
    }

    @Override
    public void dispose() 
    {
        // TODO Auto-generated method stub

    }

    @Override
    public void initialize() 
    {
        // TODO Auto-generated method stub

    }

}

BecContext.java

public class BecContext extends FREContext {

@Override
public void dispose() 
{
    // TODO Auto-generated method stub

}

@Override
public Map<String, FREFunction> getFunctions() 
{
    Map<String, FREFunction> functionMap = new HashMap<String, FREFunction>();
    functionMap.put("startScanning", new StartScanFunction());
    return functionMap;
}

}

StartScanFunction.java

private final static String TAG = StartScanFunction.class.getSimpleName();

byte[] advPacket;

public BecsterBeacon becBecMgr; 

@Override
public FREObject call(FREContext context, FREObject[] args) 
{

    //****-----BECSTER SDK START-----****//

    Log.i(TAG, "**Initializing Becster SDK**");

    //this call works
    context.dispatchStatusEventAsync("BECSTER_DUMMY", "Becster SDK has started initalizing");

    if (!context.getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) 
    {
        Log.e(TAG, "Bluetooth LE not supported or disabled");
        return null;
    }

    // Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to
    // BluetoothAdapter through BluetoothManager.
    final BluetoothManager bluetoothManager =
            (BluetoothManager) context.getActivity().getSystemService(Context.BLUETOOTH_SERVICE);

    Log.i(TAG, "Starting Becster Beacon Manager");

    becBecMgr = new BecsterBeacon(bluetoothManager, new BecNotifyHandler(context));

    Log.i(TAG, "**Becster SDK Initialized**");

    //this call works
    context.dispatchStatusEventAsync("BECSTER_DUMMY", "Becster SDK has finished initalizing");

    BecBecMgr.startLEScan();

    return null;
}

BecNotifyHandler.java(实现了 BecEvent 的函数 becsterEventNotify,从内部调用

public static final String TAG = "BecNotifyHandler"; 

private FREContext context;

public BecNotifyHandler(FREContext context)
{
    context.dispatchStatusEventAsync("BECSTER_DUMMY", "BecNotifyHandler has been initialized");
    this.context = context;
}

@Override
public void becsterEventNotify(BecPkt event) 
{
    try
    {
        Log.i(TAG, "Notifying of Becster event. Context: " + context);

        //this call ALWAYS throws the IllegalArgumentException
        context.dispatchStatusEventAsync("BECSTER_NOTIFY", "Becster notify");
        Log.i(TAG, "Notified");
    }
    catch (IllegalArgumentException e)
    {
        e.printStackTrace();
    }

}

LogCat:

07-17 10:50:33.949: I/BecNotifyHandler(17467): Notifying of Becster event. Context: com.company.sdk.BecsterContext@41e2df30
07-17 10:50:33.949: W/System.err(17467): java.lang.IllegalArgumentException
07-17 10:50:33.949: W/System.err(17467):    at com.adobe.fre.FREContext.dispatchStatusEventAsync(Native Method)
07-17 10:50:33.949: W/System.err(17467):    at com.company.sdk.BecNotifyHandler.becsterEventNotify(BecNotifyHandler.java:27)
07-17 10:50:33.949: W/System.err(17467):    at com.becster.becsterSDK.BecsterBeacon$1$1.run(BecsterBeacon.java:280)
07-17 10:50:33.949: W/System.err(17467):    at android.os.Handler.handleCallback(Handler.java:733)
07-17 10:50:33.949: W/System.err(17467):    at android.os.Handler.dispatchMessage(Handler.java:95)
07-17 10:50:33.949: W/System.err(17467):    at android.os.Looper.loop(Looper.java:136)
07-17 10:50:33.949: W/System.err(17467):    at android.app.ActivityThread.main(ActivityThread.java:5141)
07-17 10:50:33.949: W/System.err(17467):    at java.lang.reflect.Method.invokeNative(Native Method)
07-17 10:50:33.957: W/System.err(17467):    at java.lang.reflect.Method.invoke(Method.java:515)
07-17 10:50:33.957: W/System.err(17467):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
07-17 10:50:33.957: W/System.err(17467):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:611)
07-17 10:50:33.957: W/System.err(17467):    at dalvik.system.NativeStart.main(Native Method)

任何见解都非常感谢!

【问题讨论】:

    标签: android bluetooth air bluetooth-lowenergy ane


    【解决方案1】:

    context.dispatchStatusEventAsync 继续产生一些非常奇怪的结果。当我调用一次 becsterEventNotify 时,我会收到正确的消息。连续两次调用 becsterEventNotify 不会产生任何消息。因此,我仍然不确定是什么导致了问题。我怀疑线程可能存在问题,因为我曾一度使用 Thread.sleep(1000) 来查看在消息之间放置一些时间是否会有所帮助,但这会导致根本没有发送任何消息。

    如果有人好奇,我确实想出了一个解决方法。我没有使用 dispatchStatusEventAsync,而是创建了一个静态的字符串向量来保存来自信标的数据(id、电池寿命和 rssi)。

    public static Vector<String> packets = new Vector<String>();
    

    然后将此 gem 添加为函数:

    public class GetNextPacketFunction implements FREFunction 
    {
    private static final String TAG = GetNextPacketFunction.class.getSimpleName();
    
    @Override
    public FREObject call(FREContext context, FREObject[] args) 
    {
        Vector<String> packets = BecsterExtension.packets;
    
        if (packets != null && packets.size() > 0)
        {
            String nextPacket = packets.remove(packets.size() - 1);
            Log.i(TAG, "Found packet: " + nextPacket);
            try 
            {
                return FREObject.newObject(nextPacket);
            } 
            catch (FREWrongThreadException e) 
            {
                Log.e(TAG, "WRONG THREAD!");
                e.printStackTrace();
            }
        }
    
        return null;
    }
    
    }
    

    然后我实现了通知器,以便在数据包进入时保存它们:

    @Override
    public void becsterEventNotify(BecPkt event) 
    {
    
        String newPacket = btIDStr + ";" + event.getBattVal() + ";" + event.getRssiVal();
        BecsterExtension.packets.add(newPacket);
    
        Log.i(TAG, "Number of packets in queue: " + BecsterExtension.packets.size());
    
    }
    

    然后在 AS 端,我使用 Timer 每秒轮询新数据包(尚未确定这是否是最佳间隔):

                var packetTimer:Timer = new Timer(1000);
                packetTimer.addEventListener(TimerEvent.TIMER, function (e:TimerEvent):void
                {
                    var newPacket:String = getNextPacket();
    
                    if (newPacket != null)
                    {
                        var data:Array = newPacket.split(";");
    
                        var becEvent:BecEvent = new BecEvent(BecEvent.NOTIFY);
                        becEvent.id = data[0];
                        becEvent.battLife = data[1];
                        becEvent.rssi = data[2];
                        dispatchEvent(becEvent);
                    }
                });
    
                packetTimer.start();
    

    这种方法目前运行良好,我更喜欢它,因为我可以在 AS 端管理队列。

    谢谢大家!

    【讨论】: