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

Qsi*_*Qsi 6 gwt google-app-engine android gwt-rpc requestfactory

我对Android中GWT-RequestFactory的使用有疑问.为起点我使用的代码从"创建连接Android的一个项目的AppEngine" -向导(相关信息: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);
Run Code Online (Sandbox Code Playgroud)

在我想要的任何活动中,将收到MyRequestFactory的实例.(注:是的Util由向导创建的类.)但是,如果我试图让从我SyncAdapter相同的呼叫,我会得到了java.lang.RuntimeException:本RequestFactory ValidationTool必须为com.hotool.client运行. MyRequestFactory RequestFactory类型".

也许您的信息: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;
}
Run Code Online (Sandbox Code Playgroud)

RequestFactorySource中出现错误,它位于requestfactory-client.jar中, 我认为这可能是类加载器问题,但试图找出它没有成功.

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

有没有人知道是什么原因引起的?

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

Markus Neuenschwander

And*_* Ka 4

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

它发生在 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();
    }

    //...

}
Run Code Online (Sandbox Code Playgroud)

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

    //...

}
Run Code Online (Sandbox Code Playgroud)

问题是,当从 Android 上的同步适配器调用时,Thread.currentThread().getContextClassLoader() 似乎返回 null 值,因为同步适配器线程是由系统创建的,而不是由您的应用程序创建的。

我通过在创建 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);

    // ...
}
Run Code Online (Sandbox Code Playgroud)

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