Как использовать GWT-RequestFactory в Android SyncAdapter (всегда появляется ValidationTool-Error) - PullRequest
6 голосов
/ 08 ноября 2011

У меня возник вопрос об использовании GWT-RequestFactory в Android. В качестве отправной точки я использовал код из мастера «Создание Android-проекта, подключенного к AppEngine» (информация: http://code.google.com/intl/de-DE/eclipse/docs/appengine_connected_android.html), и он отлично работал.

Но теперь в моем случае я хочу расширить это приложение, чтобы использовать локальный ContentProvider с SQLite, а SyncService с SyncAdapter синхронизируют данные из ContentProvider с AppEngine с помощью RequestFactory. Теперь моя проблема заключается в следующем: я могу позвонить

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

в любой деятельности, которую я хочу, и получит экземпляр MyRequestFactory. (Примечание: Util - это класс, созданный мастером.) Но если я попытаюсь сделать такой же вызов из моего SyncAdapter, я получу java.lang.RuntimeException: RequestFactory ValidationTool должен быть запущен для типа RequestFactory com.hotool.client.MyRequestFactory ».

Возможно, для вашей информации: метод Util.getRequestFacory выглядит следующим образом:

/**
* 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;
}

Ошибка возникает в RequestFactorySource , который находится в requestfactory-client.jar Я думаю, что это может быть проблема Class-Loader, но попытался разобраться безуспешно.

Я пытался использовать ValidationTool, но, во-первых, это не помогло, а во-вторых, я обнаружил, что классы, которые будет генерировать ValidationTool, уже существуют (вероятно, благодаря обработке аннотаций, как упоминалось здесь: http://code.google.com/p/google-web-toolkit/wiki/RequestFactoryInterfaceValidation)

У кого-нибудь есть идеи, что может вызвать это?

Большое спасибо и наилучшие пожелания.

Маркус Нойеншвандер

1 Ответ

4 голосов
/ 06 января 2012

Вы правы, Марк, это проблема загрузчика классов.

Это происходит в requestfactory-client.jar, здесь соответствующий источник:

class InProcessRequestFactory extends AbstractRequestFactory {

    //...

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

    //...

}

и

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);
    }

    //...

}

Проблема в том, что Thread.currentThread (). GetContextClassLoader (), по-видимому, возвращает нулевое значение при вызове из адаптера синхронизации на Android, поскольку поток адаптера синхронизации создается системой, а не вашим приложением.

Я решил эту проблему, вызвав вручную вызов метода setContextClassLoader в методе onPerformSync перед созданием экземпляра 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);

    // ...
}

Надеюсь, это имеет смысл.Andreas

...