Потоки, атомарные логические, синхронизированные соображения проектирования для метода, который должен ждать результата

Мой код начинает становиться немного сложным для отладки, что приводит меня к мысли, что мой выбор дизайна не идеален. Я новичок в программировании на Android и хотел бы помочь с оптимизацией дизайна для оптимальной работы.

вступление

Я пишу приложение, которое использует интерфейс rfcomm для передачи данных между клиентом и устройством сервера. Клиент должен запросить определенные вещи с сервера, используя определенный ключ, затем он должен ждать, пока сервер не отправит результат обратно.

Текущий дизайн

  • Нажатие кнопки запускает запрос информации с сервера.
  • Запущен новый поток, который выполняет запрос.
  • Ключ, который является уникальным целым числом, преобразуется в байтовый массив и отправляется на сервер.
  • В потоке есть цикл while, который ожидает, чтобы конкретное логическое значение перешло с false на true, что указывает на ответ от сервера.
  • Информация получена на стороне сервера. Сервер использует ключ, чтобы определить, что делать дальше.
  • Сервер запускает поток для выполнения какого-либо запроса и в результате возвращает jsonString.
  • Сервер отправляет jsonstring, преобразованный в байтовый массив, которому предшествует тот же идентификационный ключ, обратно клиенту.
  • Клиент читает сообщение и отправляет байтовый массив в метод обработки на основе идентифицирующего ключа.
  • Метод обработки сохраняет jsonString в переменной класса и затем переворачивает логическое значение, чтобы сообщить другому потоку, что значение, которое он ожидал, было установлено.
  • Строка Json преобразуется в объект на стороне клиента. Что-то сделано с этим объектом.

Этот код в настоящее время корректно отправляет информацию на сервер, сервер правильно выполняет поиск и получает действительный результат строки json. Однако проблема возникает, когда сервер записывает свои результаты в клиент. Я получаю 20 сообщений вместо одного, и ни одно не соответствует ключу поиска...

Мои вопросы

  • Я делаю вещи эффективным способом в дизайне?
  • Могу ли я извлечь выгоду из использования synchronized ключевое слово или и Atomic Boolean, чтобы сделать мой код более потокобезопасным? Как бы я пошел на реализацию этого?
  • Существует ли максимальная длина для преобразования строк в байтовый массив? Может быть, код пытается разбить посылку для меня, и поэтому я получаю 20 разных результатов?

Соответствующий код

public class ClientSpokesmanClass {

    private final int searchKey = 2222222; //set the key to some int.
    private boolean pendingSearchResults = false;
    List<Place> places = new ArrayList<Place>();

    private final Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            switch(msg.what) {
            ...
            case MESSAGE_READ:
                //Message received from server
                readAndDistribute(msg.arg1, msg.obj);
                break;
            ... 
            }
         }
     };

   public List<Place> getPlacesFromServer(String query){
        //ask server for search results
        requestSearchFromServer(query);
        //just wait for them...
        while (pendingSearchResults){
           //just waiting
       }
        return places;
    }

    private void requestSearchFromConnectedDevice(String query) {
        if (mBluetoothState == STATE_CONNECTED){
            byte[] bites = new byte[4];
            bites = ByteBuffer.wrap(bites).putInt(searchKey).array();
            byte[] stringBytes = null;

            try {
                stringBytes = query.getBytes("UTF-8");
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                Log.e(TAG, "unsupported encoding", e);
            }

            int keyLength = bites.length;
            int stringLength = stringBytes.length;

            byte[] combined = new byte[keyLength+stringLength];
            System.arraycopy(bites, 0, combined, 0, keyLength);
            System.arraycopy(stringBytes, 0, combined, keyLength, stringLength);

            mBluetoothService.write(combined);
        }

    pendingSearchResults = true;
    }

private void receiveSearchResults(byte[] bites){

    String jsonString = "";
    PlacesJSONParser parser = new PlacesJSONParser();

     try {
         jsonString = new String(bites, "UTF-8");
     } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        Log.e(TAG, "unsupported encoding", e);
    }

     if (D) Log.d(TAG, "Json string we got is "+jsonString);

    try {
         places = parser.parse(new JSONObject(jsonString));
    } catch (JSONException e) {
         // TODO Auto-generated catch block
        Log.e(TAG, "JSON exception", e);
    }
    pendingSearchResults = false;
 }

/**
 * Reads come here first. Then, based on the key prepended to them, 
  * they then go to other methods for further work.
  * @param bytes
  * @param buffer
  */
private synchronized void readAndDistribute(int bytes, Object buffer){

    byte[] buff = (byte[]) buffer;

     int key = ByteBuffer.wrap(Arrays.copyOfRange(buff, 0, 4)).getInt();

     if (key == searchKey){
         receiveSearchResults(Arrays.copyOfRange(buff, 4, bytes));
     }else{
         //do something else
        }
    }
}

,

public class ClientUI extends Activity {
    ...
    onQueryTextSubmit(String query){
        final String queryFinal = query;
        Thread thread = new Thread(){
            public void run() {
               places = ClientSpokesmanClass.getPlacesFromServer(query);
               doSomethingWithPlaces();
            }
        };
        thread.start();
    }

}

,

public class ServerReceive {
    private searchKey = 2222222;

    ...
    //code that handles messages, reads key, and then runs doSearchAndWriteResults()
    ...

    private synchronized void doSearchAndWriteResults(byte[] bites){
        if (D) Log.d(TAG, "+++writeSearchResults");

        //Initialize query and placesString
        String query = null;
        String placesString;

        //Convert byte array to the query string
        try {
            query = new String(bites, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
           Log.e(TAG, "unsupported encoding",e);
        }

        //if the string was converted successfully...
        if (query != null){
            //Run the places query and set the json string to placesString
            if (D) Log.d(TAG, "query is "+query);
            PlacesProvider placeProvider = new PlacesProvider();
            placesString = placeProvider.getPlacesString(query);
        }

        //initialize a bite array
        byte[] stringBytes = null;
        try {
            //convert jsonString to byte array
            stringBytes = placesString.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            Log.e(TAG, "unsupported encoding",e);
        }

         //Put the search key to a byte array. I am using this key on the client side
         //to confirm that we are reading searchResults and not some other type of write.
        byte[] bite = new byte[4];
        bite = ByteBuffer.wrap(bite).putInt(searchKey).array();

        //Get the lengths of the two byte arrays
        int keyLength = bite.length;
        int stringLength = stringBytes.length;

        //combine the byte arrays for sending
        byte[] combined = new byte[keyLength+stringLength];
        System.arraycopy(bite, 0, combined, 0, keyLength);
        System.arraycopy(stringBytes, 0, combined, keyLength, stringLength);

        if (D) Log.d(TAG, "Actually writing things here...");

        //send the byte arrrays over rfcomm
        mBluetoothService.write(combined);

     }
 }

1 ответ

Посмотрите на https://github.com/gettyimages/connect_sdk_java. Именно на тестовом приложении. Он выполняет поиск, используя AsyncTask, и закрытый класс уведомляет пользовательский интерфейс через onPostExecute. Надеюсь, это продвинет вас дальше.

Другие вопросы по тегам