I personally do like you. I created a class that mounts the queue of uploads to the server, when I add a request to the end of the queue I try to send the requests if there is a connection. I also have a service that is called when the connection is changed and if there is a connection tries to run the queue. This solution is working very well.
In the Google documentation they recommend the use of Sync Adapters. When I created this part in my app I had no knowledge of this recommendation, if I had possibly tried to implement it that way. Unfortunately it is in English and is too extensive and comprehensive to summarize in a message here. You can find what you need to use a Syncadapter here:
http://developer.android.com/intl/pt-br/training/sync-adapters/index.html
CODE REQUESTED BY THE QUESTIONER
First important thing in the class is to be a Singleton that I start in the Application Oncreate, so the whole program will always have the same instance of the queue.
I create my request parameters as Jsonobject, add them to a Jsonarray with all requests and save the array as text in the same Sharedpreferences. I chose to do it this way because it is very easy to transform JSON to text and vice versa:
public void addToRequestQueue( final JSONObject request )
{
try
{
String pendingRequests = mPref.getString( Globals.PENDING_REQUESTS, "[]" );
JSONArray jArray = new JSONArray( pendingRequests );
jArray.put( request );
SharedPreferences.Editor mEditor = mPref.edit( );
mEditor.putString( Globals.PENDING_REQUESTS, jArray.toString( ) );
mEditor.apply( );
}
catch( JSONException e )
{
e.printStackTrace( );
}
runQueue( );
}
After that I have the runWhat runs the request queue. As I said my program has requests that need to be sequential, sometimes I have a queue with 2 requests, in the first the server returns essential information pro second request. Soon in case there is no connection, I will not have this information returned by the server. To make the second request I need to make sure that the first request already got its answer. So I had to create a semaphore that only allows the runTry to run if you’re not expecting any response from the server.
public void runQueue( )
{
try
{
if( semaphore )
{
return;
}
semaphore = true;
int position = 0;
String pendingRequests = mPref.getString( Globals.PENDING_REQUESTS, "[]" );
JSONArray array = new JSONArray( pendingRequests );
if( array.length( ) > position )
{
JSONObject request = array.getJSONObject( position );
String tag = request.getString( "tag" );
switch( tag )
{
case Globals.MONITOR:
{
// Se necessário adicionar informações novas ao JSONObject request
sendRequest( position, tag, request );
break;
}
.
.
.
default:
semaphore = false;
break;
}
}
else
{
semaphore = false;
}
}
catch( JSONException e )
{
semaphore = false;
e.printStackTrace( );
}
}
I use Volley to communicate with the server, but since I need to wait for the server answer, I needed to use a Requestfuture that blocks the Thread, so we can’t use the Thread UI not to lock the application:
public void sendRequest( final int position, final String tag, final JSONObject params )
{
Thread thread = new Thread( )
{
@Override
public void run( )
{
JSONObject result = syncVolleyRequest( tag, params );
if( result != null )
{
parseRequestResult( position, tag, result );
}
else
{
semaphore = false;
}
}
};
thread.start( );
}
public JSONObject syncVolleyRequest( final String tag, final JSONObject params )
{
ConnectionDetector cd = new ConnectionDetector( mContext );
if( cd.hasActiveInternetConnection( ) )
{
RequestFuture< String > futureRequest = RequestFuture.newFuture( );
StringRequest request =
new StringRequest( Request.Method.POST, NetworkConfig.SERVER_URL, futureRequest,
futureRequest )
{
@Override
protected Map< String, String > getParams( )
{
return getRequestParams( params );
}
};
request.setTag( tag );
mRequestQueue = VolleyRequestQueue.getInstance( mContext ).getVolleyRequestQueue( );
mRequestQueue.add( request );
try
{
return new JSONObject( futureRequest.get( 30, TimeUnit.SECONDS ) );
}
catch( JSONException e )
{
e.printStackTrace( );
}
catch( InterruptedException e )
{
e.printStackTrace( );
Thread.currentThread( ).interrupt( );
}
catch( ExecutionException e )
{
e.printStackTrace( );
}
catch( TimeoutException e )
{
semaphore = false;
runQueue( );
e.printStackTrace( );
return null;
}
}
semaphore = false;
return null;
}
After I get the answer I parse the result, if successful I delete the Request from the a queue and rotate it again:
private void parseRequestResult( final int position, final String tag, final JSONObject result )
{
try
{
if( ! result.getBoolean( "error" ) )
{
switch( tag )
{
case Globals.MONITOR:
.
.
.
break;
.
.
.
default:
break;
}
semaphore = false;
deleteRequest( position );
runQueue( );
}
}
catch( JSONException e )
{
e.printStackTrace( );
}
semaphore = false;
}
private void deleteRequest( int position )
{
try
{
JSONArray pivotArray = new JSONArray( );
String pendingRequests = mPref.getString( Globals.PENDING_REQUESTS, "[]" );
JSONArray array = new JSONArray( pendingRequests );
for( int i = 0; i < array.length( ); i++ )
{
if( i != position )
{
pivotArray.put( array.getJSONObject( i ) );
}
}
array = pivotArray;
SharedPreferences.Editor mEditor = mPref.edit( );
mEditor.putString( Globals.PENDING_REQUESTS, array.toString( ) );
mEditor.apply( );
}
catch( JSONException e )
{
e.printStackTrace( );
}
}
Since you will only send location, I don’t think it needs to be sequential, so you wouldn’t need to use Requestfuture or the traffic light (which is a piece of code that I found very confusing and susceptible to errors, every possibility of failure in this code I have to put Maphore = false, if forget the queue is stopped and will only run when called again. I intend to review in the future).
So, I’ve got a Syncadapter running... he’s the one who sends the data to the server. So I’m gonna go with that idea anyway, it should work out just fine. I use Syncadapter to send the data to the server, that is, I have 3 services, one to get the location another to run Syncadapter and the other is for the authentication account. Thank you for the reply.
– thalissonestrela
Can you show me some of your code that you made your queue? Thank you.
– thalissonestrela
I added the important parts of my code explained in the reply.
– Matheus de Mello
Thanks! Thank you so much. Your idea is pretty much the same as mine. Thanks so much for sharing. :)
– thalissonestrela