سؤال

I'm currently developing an android app that communicates with some other device, that acts like a server. Basically to build the application's views, I first have to send a query via a TCP connection to the server to get the info. I (successfully) execute these queries with the help of an async task:

    private class TCPQuery extends AsyncTask<String, String, String> {

        @Override
        protected String doInBackground(String... params) {
                //connect the socket send the query and receive feedback
        }

        @Override
        protected void onPostExecute(String result) {
                //parse server feedback and build the view
        }
    }

This approach works fine when it comes to single queries that are made only a couple of times during the application's lifetime. What I have trouble implementing is the following: a certain view in the application, contains seekbars. So basically, every change of the seekbar value (every time the onProgressChange method fires) must be sent to the server(no feedback this time), so it can keep track of the actual values.

How would you go about implementing this? Of course, no networking in android may be done on the main thread. But here establishing a connection, sending a message and closing the connection every time the value changes is not acceptable. Sliding the bar only a little already results in a dozen such calls in a split second.

I've tried approaching this problem by implementing a service. The service had its own socket to communicate with the server. I would connect the socket to the server and keep it open, so that I would be able to call the service's send method any time a seekbar change has been made. But that seemed to interfere with the other queries I mentioned before (the ones executed with async tasks). I couldn't connect one while the other was active. Now I'm not sure whether my service implementation was just bad, or if I am misunderstanding a crucial networking concept here.

I have thought of only sending the data onStopTrackingTouch, but that is not really what I am after. Any help would be very much appreciated!

هل كانت مفيدة؟

المحلول

Use the system clock to check when the last query has been sent, and don't send another until a certain time has elapsed. You can change seekbar's value as you want, but the query will be sent only every X milliseconds.

static long sendInterval = 600; //milliseconds

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
  long nextSend = 0;    
}

@Override
public void onProgressChanged(......) {
  if (nextSend < uptimeMillis()) {
  ...send the query and parse feedback...
  nextSend = uptimeMillis() + sendInterval ;
  }

Start with nextSend = 0, so the first time the query will be sent immediatly. Choose sendInterval value according to server's response time. Start with a high value and decrease until you see that all is working well. If the query itself and the response are small (a few bytes) consider using UDP instead of TCP, it's faster and you can use lower values of sendInterval.

نصائح أخرى

Other way to do it, different and maybe better: since the response time may vary much depending on network traffic, query complexity and server load, you can use a boolean flag. Set it to False before sending the query, set it to True after parsing the response. Use it in an If statement:

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
  boolean readyForQuery = true;    
}

@Override
public void onProgressChanged(......) {
  if (readyForQuery) {
  readyForQuery = false;
  <...asyncronous send the query, parse feedback and set readyForQuery=true;...>
  }

Consider also the worst case: when the server is down and will not respond at all to the query. Take care to find a way to set the flag True after a reasonable amount of time and/or when the query code generates an exception, otherwise you won't get further responses even when the server goes up again.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top