线程、原子布尔值、必须等待结果的方法的同步设计注意事项



我的代码开始变得有点难以调试,这让我相信我的设计选择并不理想。我是一个Android编程的新手,希望能在优化设计以实现最佳操作方面得到一些帮助。

简介

我正在编写一个使用rfcomm接口在客户端和服务器设备之间传输数据的应用程序。客户端需要使用特定的密钥向服务器请求某些内容,然后需要等待,直到服务器发回结果。

当前设计

  • 按下一个按钮就会触发对服务器信息的请求
  • 将启动一个执行请求的新线程
  • 作为唯一整数的密钥被转换为字节数组并发送到服务器
  • 线程有一个while循环,它正在等待一个特定的布尔值从false翻转为true,指示服务器返回响应
  • 在服务器端接收信息。服务器使用密钥来确定下一步要做什么
  • 服务器启动一个线程来运行一些查询,结果得到一个jsonString
  • 服务器将转换为字节数组的jsonstring发送回客户端,该数组以相同的标识密钥为前缀
  • 客户端读取消息,并将字节数组发送到基于标识密钥的处理方法
  • Handling方法将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);
     }
 }

看看https://github.com/gettyimages/connect_sdk_java.特别是在测试应用程序中。它使用AsyncTask执行搜索,私有类通过onPostExecute通知UI。希望这能让你走得更远。

相关内容

  • 没有找到相关文章

最新更新