【问题标题】:How to properly handle APP_MSG_BUSY in pebble?如何在 pebble 中正确处理 APP_MSG_BUSY?
【发布时间】:2014-07-01 14:49:17
【问题描述】:

我正在向我的 Pebble 发送大量数据,但其中一些数据不断丢失。我意识到这部分是由于缓冲区大小不足以容纳我发送它的PebbleDictionary,所以我把它分成多个小块。但是,这会导致出现APP_MSG_BUSY 错误的问题。

这可能会发生,因为我不是在等待来自 pebble 的 ack/nack,而是只是背靠背地发送数据。因此,我尝试添加 ack/nack 处理程序以及队列,但由于我的 sendMessage() 函数在等待 ack/nack 处理程序时阻塞了主 UI 线程,我无法让它工作。

因此,我的问题是处理APP_MSG_BUSY 这个特定实例的最佳方法是什么。我不希望我发送的任何数据被丢弃,这意味着要么在发送下一条数据之前等待确认,要么在收到 nack 后重新发送。如果可能的话,我想避免线程,但我一直无法想出一个不涉及线程的合理解决方案。

编辑:据我所知,pebble 代码中没有错误。它将使用正确的密钥请求数据,并且会(自动)确认 android 应用程序发送的任何消息。

如果你愿意,我已经在下面发布了我的代码:

当前代码(android 应用的相关部分):

public class MainActivity extends ActionBarActivity {

    private PebbleDataReceiver mReceiver;
    private PebbleAckReceiver ackReceiver;
    private PebbleNackReceiver nackReceiver;

    ConcurrentLinkedQueue<BoolDictionary> queue = new ConcurrentLinkedQueue<BoolDictionary>();

    final UUID PEBBLE_APP_UUID = UUID.fromString("2ef1h2ba-1a59-41f7-87da-797beca4d395");
    final static int CONTACTS_NEEDED = 0x0;
    final static int CONTACTS_SIZE = 0x1;
    final static int NEW_MESSAGE = 0x2;
    final static int NEW_CONVERSATION = 0x3;
    final static int RECORD_NEW_MESSAGE = 0x4;

    Thread sendMessages = new Thread(){
        public void run(){

            while (true){
                PebbleKit.sendDataToPebbleWithTransactionId(getApplicationContext(), PEBBLE_APP_UUID, queue.element().getDict(), queue.element().getTransId());

                try {
                    queue.element().wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                }

                if (queue.element().isAkced()){
                    break;
                }
            }

            queue.remove();
            if (queue.size() > 0){
                run();
            }
            else if (queue.size() == 0){
                queue.element().wait();
            }
        }
    };

    public BoolDictionary createBoolDictionary(int key, int data){
        PebbleDictionary dict = new PebbleDictionary();
        dict.addInt32(key, data);
        return new BoolDictionary(dict);
    }

    public BoolDictionary createBoolDictionary(int key, String data){
        PebbleDictionary dict = new PebbleDictionary();
        dict.addString(key, data);
        return new BoolDictionary(dict);
    }

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

        ackReceiver = new PebbleAckReceiver(PEBBLE_APP_UUID) {
            @Override
            public void receiveAck(Context context, int transactionId) {
                if (queue.element().getTransId() == transactionId){
                    queue.element().setAkced(true);
                    queue.element().notifyAll();
                }               
            }
        };

        nackReceiver = new PebbleNackReceiver(PEBBLE_APP_UUID){
            @Override
            public void receiveNack(Context context, int transactionId) {
                if (queue.element().getTransId() == transactionId){
                    queue.element().setAkced(false);
                    queue.element().notifyAll();
                }
            }           
        };

        mReceiver = new PebbleDataReceiver(PEBBLE_APP_UUID) {
            @Override
            public void receiveData(Context context, int transactionId, PebbleDictionary data) {

                PebbleKit.sendAckToPebble(context, transactionId);

                if (data.contains(CONTACTS_NEEDED)){                    

                    //test data
                    queue.add(createBoolDictionary(0x5, "Entry 1"));
                    queue.add(createBoolDictionary(0x6, "Entry 2"));
                    queue.add(createBoolDictionary(0x7, "Entry 3"));
                    queue.add(createBoolDictionary(0x8, "Entry 4"));
                    queue.add(createBoolDictionary(0x9, "Entry 5"));
                    queue.element().notifyAll();
                }
            }

        };

        PebbleKit.registerReceivedDataHandler(this, mReceiver);
        PebbleKit.registerReceivedAckHandler(this, ackReceiver);
        PebbleKit.registerReceivedNackHandler(this, nackReceiver);
    }

    @Override
    protected void onPause(){
        super.onPause();
        unregisterReceiver(mReceiver);
        unregisterReceiver(ackReceiver);
        unregisterReceiver(nackReceiver);
    }
}

布尔字典:

public class BoolDictionary extends PebbleDictionary{
    private PebbleDictionary dict;
    private boolean akced = false;
    private int transId;

    BoolDictionary(PebbleDictionary data){
        this.setDict(data);
        setTransId(new Random().nextInt(Integer.MAX_VALUE));
    }

    [insert getters and setters here]
}

这会产生以下错误:

07-01 10:43:06.096: E/AndroidRuntime(21941): FATAL EXCEPTION: Thread-5310
07-01 10:43:06.096: E/AndroidRuntime(21941): Process: com.example.firstapp, PID: 21941
07-01 10:43:06.096: E/AndroidRuntime(21941): java.util.NoSuchElementException
07-01 10:43:06.096: E/AndroidRuntime(21941):    at java.util.AbstractQueue.element(AbstractQueue.java:107)
07-01 10:43:06.096: E/AndroidRuntime(21941):    at com.example.firstapp.MainActivity$1.run(MainActivity.java:366)

【问题讨论】:

    标签: java android pebble-watch pebble-sdk


    【解决方案1】:

    当 Pebble 收到您的新数据包但蓝牙缓冲区中已经有一条消息表明您的应用还没有来得及读取时,会返回错误 APP_MSG_BUSY

    要理解这一点,您需要记住 Pebble 上的内存很紧,因此系统无法缓冲传入的消息,因为这会很快占用大量内存。相反,它会拒绝该消息。

    避免此问题的最佳策略是在发送另一条消息之前等待 Pebble 的 ACK/NACK。似乎您已经这样做了,但另一个提示是确保您将多个键分组到一条消息中,而不是为每个键发送一条消息(这可以最大限度地使用传入缓冲区,但当然限制是该缓冲区的大小)。

    【讨论】:

    • 似乎即使使用最新的 SDK4 也没有很好的方法将 ack 与原始发送相关联。在我发送多种消息类型的情况下,很难区分我发送了什么以及接下来要发送什么。静态变量是解决这个问题的糟糕方法。上面的解决方案虽然聪明,但仍然会导致 transactionId 冲突。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多