2

問題は簡単です。Android では、ライブラリ関数を呼び出す必要があるメソッドがあります。この呼び出しは、処理する必要があるコールバックを通知します。メソッドから戻る前に、そのコールバックが通知されるのを待つ必要があります。

モニター オブジェクトの wait() メソッドと notify() メソッドがうまくいくと思いました。そうではありません。

Connection基本的に、呼び出し元のメソッドでインスタンス化する監視オブジェクトが呼び出されます。次に、このメソッドは、Android ライブラリ メソッドを呼び出してオブジェクトを「登録解除」するループを実行します。残念ながら、このメソッドへの応答は何らかのコールバックで提供されます。そのため、このメソッドを使用しConnection.wait(10000)てコールバックを待機し、コールバックでは、connection.notify()完了したときに通知するために使用します (もちろん、すべて同期されています)。ただし、connection.notify()は をリリースしませんconnection.wait(10000)。Android logcat から、登録解除が成功したことがわかりますが、次の登録解除タスクが試行されるまで、常に 10 秒待たなければなりません。

呼び出しメソッドとコールバックのコードは次のとおりです。これが失敗するという私の推論で、私はなんてばかげた仮定をしていますか。私が見る限り、呼び出し元のメソッド (スレッド) は確実に監視オブジェクトを所有し、connection.wait(10000)!のコールバックにそれを渡します。

たぶん、この問題に対して完全に間違ったアプローチを使用していますか? (私が欲しいのは、すべての登録解除が完了するまで発信者をブロックする方法です。)

public void clearRegistrations()
{
    connection = new Connection();
    // Tell the callback to notify() when a result is obtained
    connection.setUseNotify(true);
    for(BluetoothHealthAppConfiguration btConfig : btHealthAppConfigs)
    {
        // Initialize Connection object to not connected
        connection.setConnectionState(false);
        if(btHealth.unregisterAppConfiguration(btConfig))
        {
            try
            {
                synchronized (connection) 
                {
                    connection.wait(10000);
                    // See if we were signaled or timed out
                    if(!connection.getConnectionState())
                    {
                        Log.i(TAG, "Unregistration attempt timed out or failed; trying next un-registration");
                    }
                }
            }
            // This should not happen
            catch(InterruptedException ie)
            {
                Log.i(TAG, "The InterrupedException is signaled.");
            }
            // This should not happen.
            catch(IllegalMonitorStateException ime)
            {
                Log.i(TAG, "wait() method threw an IllegalMonitorStateException. Message: " + ime.getMessage());
            }
        }
        else
        {
            Toast.makeText(context, "Un-Registration API returned failure", Toast.LENGTH_SHORT).show();
        }
    }
    btHealthAppConfigs.clear();
    connection.setConnectionState(false);
    connection.setUseNotify(false);
}

コールバックは次のとおりで、上記のメソッドと同じクラスですが、Android で非常に人気のある「onSomeEvent()」の 1 つです。

    public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration btAppConfig, int status)
    {
        if (status == BluetoothHealth.APP_CONFIG_UNREGISTRATION_FAILURE)
        {
            Log.i(TAG, "Un-Registration of the Bluetooth Health Application failed");
            if(connection.useNotify() == true)
            {
                synchronized (connection)
                {
                    Log.i(TAG, "Signal unregistration failure");
                    // just indicate signaled
                    connection.setConnectionState(true);
                    connection.notify();
                }
            }
        }
        else if(status == BluetoothHealth.APP_CONFIG_UNREGISTRATION_SUCCESS)
        {
            Log.i(TAG, "Un-Registration of the Bluetooth Health Application successful");
            if(connection.useNotify() == true)
            {
                synchronized (connection)
                {
                    Log.i(TAG, "Signal unregistration success");
                    connection.setConnectionState(true);
                    connection.notify();
                }
            }
        }
    }
4

1 に答える 1

0

このコードには間違っている可能性のあるものがたくさんあります: assylias はそれらのほとんどを持っています。明らかなことは、notify の代わりに notifyAll を使用する必要があることです。notify は、ロックを待機しているスレッドを再起動します。notifyAll はそれらをすべて再起動します。

useNotify と setConnectionState も同期する必要があります。また、ロックしている接続のインスタンスが両方のセクションで同じであり、通知を呼び出すのと同じであることを保証する必要があります。最後に、notify の呼び出しが wait の呼び出しの後に実際に発生することを保証する必要があります。

アプローチに関しては、このような低レベルのツールを使用するときはいつでも、より良い方法がないかどうか疑問に思うはずです。これをより簡単に行うことができるいくつかの高レベルの構造があります。コールバックを待たないように、コードを再設計することをお勧めします。呼び出しを行い、状態をどこかにパークし、発生したときにコールバックを処理します。

于 2013-02-17T15:58:02.687 に答える