Search code examples
androidconflictazure-mobile-services

Stop execution until User selects a button from the Alert Dialog


In my Android application i use a conflictHandler class inorder to detect conflicts between the records of the mobile device's DB and the Server's DB. When a conflict is detected,i want to display an Alert Dialog so that the user can choose which record version will "win"(Server's or Mobile Device's). I have put the code of the Alert Dialog in the class of the conflictHandler, so when a conflict is detected the Alert Dialog pops up. The problem is that the code execution doesn't stop when the Alert Dialog pops up, so that the user can select which action will be done. It always returns the serverItem.

private class ConflictResolvingSyncHandler implements MobileServiceSyncHandler {

    @Override
    public JsonObject executeTableOperation(
            final RemoteTableOperationProcessor processor, final TableOperation operation)
            throws MobileServiceSyncHandlerException {

        final JsonObject clientItem = processor.getItem().getAsJsonObject();

        MobileServicePreconditionFailedExceptionBase ex = null;
        final JsonObject[] result = {null};
        try {
            result[0] = operation.accept(processor);
        } catch (MobileServicePreconditionFailedExceptionBase e) {
            ex = e;
        } catch (Throwable e) {
            ex = (MobileServicePreconditionFailedExceptionBase) e.getCause();
        }

        if (ex != null) {
            // A conflict was detected; let's force the server to "win"
            // by discarding the client version of the item
            final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
                    context);

            // set title
            alertDialogBuilder.setTitle("Conflict Detected");

            // set dialog message
            final MobileServicePreconditionFailedExceptionBase finalEx = ex;
            alertDialogBuilder
                    .setMessage("Choose winner")
                    .setCancelable(false)
                    .setPositiveButton("Server",new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog,int id) {
                            // if this button is clicked, Server wins
                            JsonObject serverItem = finalEx.getValue();

                            if (serverItem == null) {
                                // Item not returned in the exception, retrieving it from the server
                                try {
                                    serverItem = mClient.getTable(operation.getTableName()).lookUp(operation.getItemId()).get();
                                } catch (Exception e) {
                                    try {
                                        throw new MobileServiceSyncHandlerException(e);
                                    } catch (MobileServiceSyncHandlerException e1) {
                                        e1.printStackTrace();
                                    }
                                }
                            }
                            result[0] = serverItem;

                        }
                    })
                    .setNegativeButton("Client",new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog,int id) {
                            // if this button is clicked, Client wins
                            result[0]=clientItem;
                        }
                    });

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // create alert dialog
                    AlertDialog alertDialog = alertDialogBuilder.create();

                    // show it
                    alertDialog.show();

                }
            });
        }

        return result[0];

    }

    @Override
    public void onPushComplete(MobileServicePushCompletionResult result)
            throws MobileServiceSyncHandlerException {
    }
}

Solution

  • You need to block the thread which is executing the executeTableOperation until the user clicks something in the dialog. For example, using a CountDownLatch, as in the code below:

    private class ConflictResolvingSyncHandler implements MobileServiceSyncHandler {
    
        @Override
        public JsonObject executeTableOperation(
                final RemoteTableOperationProcessor processor, final TableOperation operation)
                throws MobileServiceSyncHandlerException {
    
            final JsonObject clientItem = processor.getItem().getAsJsonObject();
    
            MobileServicePreconditionFailedExceptionBase ex = null;
            final JsonObject[] result = {null};
            try {
                result[0] = operation.accept(processor);
            } catch (MobileServicePreconditionFailedExceptionBase e) {
                ex = e;
            } catch (Throwable e) {
                ex = (MobileServicePreconditionFailedExceptionBase) e.getCause();
            }
    
            if (ex != null) {
                // A conflict was detected; let's make the client choose who "wins"
                final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
                        context);
    
                final CountDownLatch latch = new CountDownLatch(1);
    
                // set title
                alertDialogBuilder.setTitle("Conflict Detected");
    
                // set dialog message
                final MobileServicePreconditionFailedExceptionBase finalEx = ex;
                alertDialogBuilder
                        .setMessage("Choose winner")
                        .setCancelable(false)
                        .setPositiveButton("Server",new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,int id) {
                                // if this button is clicked, Server wins
                                JsonObject serverItem = finalEx.getValue();
    
                                if (serverItem == null) {
                                    // Item not returned in the exception, retrieving it from the server
                                    try {
                                        serverItem = mClient.getTable(operation.getTableName()).lookUp(operation.getItemId()).get();
                                    } catch (Exception e) {
                                        try {
                                            throw new MobileServiceSyncHandlerException(e);
                                        } catch (MobileServiceSyncHandlerException e1) {
                                            e1.printStackTrace();
                                        }
                                    }
                                }
                                result[0] = serverItem;
                                latch.countDown();
                            }
                        })
                        .setNegativeButton("Client",new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,int id) {
                                // if this button is clicked, Client wins
                                result[0] = clientItem;
                                latch.countDown();
                            }
                        });
    
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // create alert dialog
                        AlertDialog alertDialog = alertDialogBuilder.create();
    
                        // show it
                        alertDialog.show();
    
                    }
                });
    
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            return result[0];
    
        }
    
        @Override
        public void onPushComplete(MobileServicePushCompletionResult result)
                throws MobileServiceSyncHandlerException {
        }
    }