2014-11-14 2 views
3

Android 애플리케이션에서 conflictHandler 클래스를 사용하여 모바일 장치의 DB 레코드와 서버 DB 간의 충돌을 감지합니다. 충돌이 감지되면 경고 대화 상자를 표시하여 사용자가 어떤 기록 버전이 서버 (또는 서버) 또는 "모바일 장치"에서 "이기게 될지"를 선택할 수 있습니다. 경고 대화 상자의 코드를 conflictHandler 클래스에 넣었습니다. 충돌이 감지되면 경고 대화 상자가 나타납니다. 문제는 경고 대화 상자가 나타나면 코드 실행이 멈추지 않아 사용자가 수행 할 작업을 선택할 수 있다는 것입니다. 항상 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 { 
    } 
} 
+0

MobileServiceSyncHandler 코드를 넣을 수 있습니까? –

+0

MobileServiceSyncHandler의 코드는 Windows Azure 모바일 서비스 패키지의 mobileservices-2.0.1-beta.jar에 있으며 불행히도 나는 단지 인터페이스 만 볼 수 있습니다. – Fivos

답변

1

대화 상자에서 사용자가 무언가를 클릭 할 때까지 executeTableOperation을 실행중인 스레드를 차단해야합니다. 예를 들어, 다음의 코드 에서처럼 CountDownLatch 사용 :

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 { 
    } 
} 
1

난 잠시 루프 참 값으로 "루프"라 불리는 부울 변수를 추가 실행을 정지합니다. 사용자가 경고 대화 상자에서 단추를 선택하면 "loop"변수가 false가됩니다. 내가 추가 한 코드는 굵게 표시됩니다. 나는이 관행을 피해야한다고 믿지만.

private class ConflictResolvingSyncHandler implements MobileServiceSyncHandler { 

    **private boolean loop = true;**  

    @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 
      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(true) 
        .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; 
          **loop = false;**         
         } 
        }) 
        .setNegativeButton("Client",new DialogInterface.OnClickListener() { 
         public void onClick(DialogInterface dialog,int id) { 
          ToDoItem item = new ToDoItem(); 
          // if this button is clicked, Client wins 
          result[0] = clientItem; 
          // Convert Json object to an item of my class 
          item.setId(clientItem.get("id").getAsString()); 
          item.setText(clientItem.get("text").getAsString()); 
          item.setComplete(clientItem.get("complete").getAsBoolean()); 
          // update server's table 
          updateItem(item); 

          new AsyncTask<Void, Void, Void>() { 

           @Override 
           protected Void doInBackground(Void... params) { 
            try { 
             // send changes to the server DB 
             mClient.getSyncContext().push().get(); 

             // get query answer from the server DB 
             mToDoTable.pull(mPullQuery).get(); 
             refreshItemsFromTable(); 
            } catch (final Exception exception) { 
             runOnUiThread(new Runnable() { 
              @Override 
              public void run() { 
               createAndShowDialog(exception, "Error"); 
              } 
             }); 
            } 
            return null; 
           } 

          }.execute(); 

          **loop = false;** 

         } 
        }); 

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

        // show it 
        alertDialog.show(); 

       } 
      }); 


     } 
     **while(loop){}** 


     return result[0]; 

    } 





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


} 
+0

루프를 수행하는 동안 주 스레드가 계속 작동하기 때문에 권장 솔루션이 아닙니다. 필자는 사용자 입력이 SyncHandler에서 값을 반환 할 때까지 기다리는 동안 이전의 응답 코드와 작업 상태를 디버깅했습니다. 전제 조건 실패 예외가 감시되고 CountDownLatch가 초기화되었는지 확인 하시겠습니까? – marianosz

관련 문제