如何在Android SyncAdapter中使用GWT-RequestFactory(总是得到ValidationTool-Error)

时间:2011-11-08 10:59:07

标签: android google-app-engine gwt gwt-rpc requestfactory

我对Android中GWT-RequestFactory的使用有疑问。作为一个起点,我使用了“创建一个AppEngine连接的Android-Project”-Wizard(信息:http://code.google.com/intl/de-DE/eclipse/docs/appengine_connected_android.html)中的代码,它运行得很好。

但是在我的情况下,我希望扩展此应用程序以使用带有SQLite的本地ContentProvider和带SyncAdapter的SyncService使用RequestFactory将ContentProvider中的数据同步到AppEngine。 现在我的问题如下:我可以打电话

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

在我想要的任何活动中,将收到MyRequestFactory的实例。 (注意:Util是由向导创建的类。)但是如果我尝试从我的SyncAdapter进行相同的调用,我会得到一个     java.lang.RuntimeException:必须为com.hotool.client.MyRequestFactory RequestFactory类型“。

运行RequestFactory ValidationTool。

也许您的信息: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 中 我认为,这可能是一个类加载器问题,但试图找出它没有成功。

我尝试使用ValidationTool,但首先它没有帮助,其次我发现,ValidationTool将生成的类已经到位(可能由于此处提到的注释处理:http://code.google.com/p/google-web-toolkit/wiki/RequestFactoryInterfaceValidation

有人知道可能导致这种情况的原因吗?

非常感谢和最诚挚的问候。

Markus Neuenschwander

1 个答案:

答案 0 :(得分:4)

你是对的Mark,这是一个类加载器问题。

它发生在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上的同步适配器调用时返回空值,因为同步适配器线程是由系统创建的,而不是由您的应用程序创建的。

我通过在创建requestfactory实例之前调用onPerformSync方法中的手动调用setContextClassLoader来解决这个问题:

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

    // ...
}

我希望这是有道理的。 安德烈亚斯