2011-11-08 8 views
6

Tengo una pregunta sobre el uso de GWT-RequestFactory en Android. Como punto de partida utilicé el código del asistente "Crear un AppEngine conectado Android Project" (información: http://code.google.com/intl/de-DE/eclipse/docs/appengine_connected_android.html) y funcionó muy bien.Cómo usar GWT-RequestFactory en Android SyncAdapter (obteniendo siempre ValidationTool-Error)

Pero ahora en mi caso quiero extender esta aplicación para usar un ContentProvider local con SQLite y un SyncService con SyncAdapter sincronizar los datos de ContentProvider con el AppEngine usando RequestFactory. Ahora mi problema es el siguiente: puedo llamar

MyRequestFactory requestFactory = Util.getRequestFactory(mContext, MyRequestFactory.class); 

en cualquier actividad que quiero y voy a recibir una instancia de MyRequestFactory. (Nota: Util es una clase creada por el Asistente). Pero si intento hacer la misma llamada desde mi SyncAdapter, obtendré una java.lang.RuntimeException: RequestFactory ValidationTool se debe ejecutar para el com.hotool.client .MyRequestFactory RequestFactory tipo ".

Tal vez para su información: El método Util.getRequestFacory tiene este aspecto: se produce

/** 
* Creates and returns an initialized {@link RequestFactory} of the given 
* type. 
*/ 
public static <T extends RequestFactory> T getRequestFactory(
     Context context, Class<T> factoryClass) { 

    T requestFactory = RequestFactorySource.create(factoryClass); 

    SharedPreferences prefs = getSharedPreferences(context); 
    String authCookie = prefs.getString(Util.AUTH_COOKIE, null); 

    String uriString = Util.getBaseUrl(context) + RF_METHOD; 
    URI uri; 
    try { 
     uri = new URI(uriString); 
    } catch (URISyntaxException e) { 
     Log.w(TAG, "Bad URI: " + uriString, e); 
     return null; 
    } 
    requestFactory.initialize(new SimpleEventBus(), 
      new AndroidRequestTransport(uri, authCookie)); 

    return requestFactory; 
} 

El error en RequestFactorySource que se encuentra en el RequestFactory-client.jar creo que esto puede ser un problema de cargador de clase, pero traté de resolverlo sin éxito.

He intentado utilizar el ValidationTool pero primero de todo es que no ayudó y en segundo lugar que descubrí, que las clases del ValidationTool va a generar ya están en su lugar (probablemente gracias a la anotación de procesamiento como se ha mencionado aquí: http://code.google.com/p/google-web-toolkit/wiki/RequestFactoryInterfaceValidation)

¿Alguien tiene una idea de lo que podría causar esto?

Muchas gracias y saludos cordiales.

Markus Neuenschwander

+0

Me encuentro con el mismo error, encontré algo en http://how2code.wordpress.com/2011/12/02/error-the-requestfactory-validationtool-must-be-run-for-gwt- 2-4 /, pero eso no resuelve el problema para mí. – bembii

Respuesta

4

Está Marcos derecha, se trata de una cuestión de clase-loader.

Sucede en el RequestFactory-client.jar, aquí la fuente correspondiente:

class InProcessRequestFactory extends AbstractRequestFactory { 

    //... 

    public InProcessRequestFactory(Class<? extends RequestFactory> requestFactoryInterface) { 
     this.requestFactoryInterface = requestFactoryInterface; 
     deobfuscator = 
      Deobfuscator.Builder.load(requestFactoryInterface, 
       Thread.currentThread().getContextClassLoader()).build(); 
    } 

    //... 

} 

y

public class Deobfuscator { 

    //... 

    public static class Builder { 
     public static Builder load(Class<?> clazz, ClassLoader resolveClassesWith) { 
      Throwable ex; 
      try { 
       Class<?> found; 
       try { 
        // Used by the server 
        found = Class.forName(clazz.getName() + GENERATED_SUFFIX, false, resolveClassesWith); 
       } catch (ClassNotFoundException ignored) { 
        // Used by JRE-only clients 
        found = Class.forName(clazz.getName() + GENERATED_SUFFIX_LITE, false, resolveClassesWith); 
       } 
       Class<? extends Builder> builderClass = found.asSubclass(Builder.class); 
       Builder builder = builderClass.newInstance(); 
       return builder; 
      } catch (ClassNotFoundException e) { 
       throw new RuntimeException("The RequestFactory ValidationTool must be run for the " 
        + clazz.getCanonicalName() + " RequestFactory type"); 
      } catch (InstantiationException e) { 
      ex = e; 
     } catch (IllegalAccessException e) { 
      ex = e; 
     } 
     throw new RuntimeException(ex); 
    } 

    //... 

} 

El problema es que Thread.currentThread() getContextClassLoader() parece volver. un valor nulo cuando se llama desde el adaptador de sincronización en Android, porque el subproceso Adaptador de sincronización es creado por el sistema, no por su aplicación.

He resuelto esto llamando manualmente llamando setContextClassLoader en el método onPerformSync antes de crear una instancia de RequestFactory:

@Override 
public void onPerformSync(final Account account, Bundle extras, 
     String authority, final ContentProviderClient provider, 
     final SyncResult syncResult) { 

    Thread.currentThread().setContextClassLoader(mContext.getClassLoader()); 

    // ... 

    MyRequestFactory requestFactory = Util.getRequestFactory(mContext, 
      MyRequestFactory.class, acsidToken); 

    // ... 
} 

Espero que esto tenga sentido. Andreas

+1

¡Gracias! Eso resolvió el problema. Lo ejecuté justo antes de que respondieras la pregunta aquí. Gracias de cualquier manera. – Qsi

+0

Wounderful Answer. ¡Salva mi proyecto! –

+0

Increíble Andreas! Esto solucionó un problema extremadamente difícil. – aez