4

I have created an IntentService as follows:

    public class OrdersSyncService extends IntentService {

    private static final String TAG = OrdersSyncService.class.getSimpleName();

    private Order orderObject;

    public OrdersSyncService() {
        super("OrdersSyncService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        //Util.showToast(getApplicationContext(), "Syncing Orders........");
        Log.d(TAG, "I'm running....");
        syncOrders();
    }

    private void syncOrders() {

        Database database = CouchBaseHelper.openCouchBaseDB(this);
        JSONArray ordersJsonArray = new JSONArray(CouchBaseHelper.retrieveNotSyncedOrders(database));
        if (ordersJsonArray.length() != 0) {
            uploadOrders(ordersJsonArray.toString());
            Log.d(TAG, "Orders syncing started.");
        } else {
            Log.d(TAG, "Nothing to sync.");
        }
    }

    private void uploadOrders(String ordersJsonArray) {

        RetrofitApi.ApiInterface apiInterface = RetrofitApi.getApiInterfaceInstance();
        final Call<Order> uploadOrders = apiInterface.uploadOrders(
                ordersJsonArray,
                Util.getDeviceId(this),
                AppPreference.getString(this, AppPreference.USER_ID)
        );

        uploadOrders.enqueue(new Callback<Order>() {
            @Override
            public void onResponse(Call<Order> call, Response<Order> response) {

                if (response.isSuccessful()) {

                    if (response.body().getStatus().equals("success")) {

                        orderObject = response.body();

                        Log.d(TAG, "Server Response : " + orderObject.getMobileOrderIds());

                        boolean flag = updateOrders(orderObject);

                        if (flag) {
                            Log.d(TAG, "Orders Synced And Updated.");
                            EventBus.getDefault().post(new SyncFinished(true));

                        } else {
                            Log.d(TAG, "Orders Synced But Update Failed.");
                        }

                    } else {

                        Log.d(TAG, response.body().getMessage());

                    }

                } else {

                    Log.d(TAG, "Some Error. Sync Failed.");

                }

            }

            @Override
            public void onFailure(Call<Order> call, Throwable t) {
                Log.d(TAG, "Network problem. Sync Failed.");
                //Log.d("VICKY",call.request().url().toString());

            }
        });
    }

    private boolean updateOrders(Order order) {
        Database database = CouchBaseHelper.openCouchBaseDB(this);
        boolean flag = CouchBaseHelper.updateOrders(database, order);
        return flag;
    }
}

What it does is, it makes a network request and after the network request it updates the database(i'm using couchbaselite for android) with the response. Now the problem is its executing parallely when I make multiple requests to it. The android documentation clearly states that : Creating a Background Service

Work requests run sequentially. If an operation is running in an IntentService, and you send it another request, the request waits until the first operation is finished.

I'm calling this service from onResume method of an Activity. So whenever the activity resumes this service is called :

@Override
protected void onResume() {

    super.onResume();

    Intent ordersSyncServiceIntent = new Intent(SellerHomeActivity.this, OrdersSyncService.class);
    startService(ordersSyncServiceIntent);

}

I don't know what the problem is. I think it has something to do with Retrofit library that I'm using to make network requests which are async. Please help.

Ilya Tretyakov
  • 6,848
  • 3
  • 28
  • 45
Vicky
  • 1,807
  • 5
  • 23
  • 34

1 Answers1

5

You are doing it asynchronously in this line:

uploadOrders.enqueue(new Callback<Order>() {...});

Use execute() method for doing it synchronously.

azizbekian
  • 60,783
  • 13
  • 169
  • 249
Ilya Tretyakov
  • 6,848
  • 3
  • 28
  • 45
  • Ok, I know I'm doing it asynchronously but what exactly is causing my IntentService to run parallely? Can you please elaborate on this. – Vicky Feb 14 '17 at 10:10
  • 2
    @Vicky, you are spawning your job in another thread from the IntentService. IntentService runs, let's say thread 4, and you are running your network call on thread let's say 6. Thus, you do not make use of IntentService class. In that case you may use Service. – azizbekian Feb 14 '17 at 10:14
  • @azizbekian, I got your point that I'm creating another thread inside my IntentService, but the `Callback` from `Retrofit` should get executed on IntentService thread, right? – Vicky Feb 14 '17 at 10:20
  • `enqueue` runs your callback on the thread that this action was performed, but the actual http request happens on another thread, that Retrofit creates for you. You have to perform `uploadOrders.execute()` in order to run this request on this thread. – azizbekian Feb 14 '17 at 10:22
  • I got this from Retrofit Documentation : ` public interface Callback Communicates responses from a server or offline requests. One and only one method will be invoked in response to a given request. Callback methods are executed using the Retrofit callback executor. When none is specified, the following defaults are used: Android: Callbacks are executed on the application's main (UI) thread. JVM: Callbacks are executed on the background thread which performed the request. ` What does this mean? – Vicky Feb 14 '17 at 10:26
  • In your case it means that your callback will be run on main thread, but the network operation will happen on another thread. – azizbekian Feb 14 '17 at 10:29
  • So if I use `execute` instead of `enqueue` my IntentService will stop running parallely? Is that right? – Vicky Feb 14 '17 at 10:33
  • @Vicky, you got it! – azizbekian Feb 14 '17 at 10:34
  • Ok, I'll try this. – Vicky Feb 14 '17 at 10:35