首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >非常奇怪的NullPointerException in RoboVM

非常奇怪的NullPointerException in RoboVM
EN

Stack Overflow用户
提问于 2015-06-06 22:52:56
回答 2查看 243关注 0票数 0

如果我使用任何RoboVM非空参数调用以下方法:

代码语言:javascript
复制
public static void runOnUiThread(final Runnable runnable) {
    System.out.println("Inside runOnUiThread():");
    System.out.println("  Null-check: "+(runnable==null));

    NSOperation operation = new NSOperation() {

        @Override
        public void main() {
            System.out.println("Inside main():");
            System.out.println("  Null-check: "+(runnable==null));
            runnable.run();                 // NullPointerException here?!? How???
            System.out.println("  main() completed");
        }
    };

    NSOperationQueue.getMainQueue().addOperation(operation);        
}

它的产出如下:

代码语言:javascript
复制
Inside runOnUiThread():
  Null-check: false
Inside main():
  Null-check: true
java.lang.NullPointerException
    at RoboVMTools$1.main(RoboVMTools.java)
    at org.robovm.apple.foundation.NSOperation.$cb$main(NSOperation.java)
    at org.robovm.apple.uikit.UIApplication.main(Native Method)
    at org.robovm.apple.uikit.UIApplication.main(UIApplication.java)
    at Main.main(Main.java)

到底怎么回事?更重要的是,我该如何解决这个问题呢?

  • 我试着在operation.addStrongRef(runnable);之前添加NSOperationQueue...。没什么区别。
  • 我还尝试将匿名内部类移动到具有private final字段的自己的类中,以存储传递给构造函数的runnable。同样的结果。

我是不是错过了一些显而易见的东西?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-06-07 07:06:54

你说的GC是对的。在从Objective端调用操作之前,您的NSOperation实例是垃圾收集的。当NSOperationQueue调用到NSOperation端时,将创建一个新的NSOperation匿名类实例,它没有对Runnable实例的引用,而是对null的引用,其结果是抛出一个NullPointerException

使用addStrongRef()解析它的方式是正确的,不过只有mainQueue.addStrongRef(operation)和相应的removeStrongRef()调用就足够了:

代码语言:javascript
复制
public static void runOnUiThread(final Runnable runnable) {

    final NSOperationQueue mainQueue = NSOperationQueue.getMainQueue();

    NSOperation operation = new NSOperation() {

        @Override
        public void main() {
            runnable.run();
            mainQueue.removeStrongRef(this);
        }
    };

    mainQueue.addStrongRef(operation);
    mainQueue.addOperation(operation);      
}

这将防止Java实例(以及任何像operation一样可以从它访问的Runnable对象)成为GCed,直到目标-C NSOperationQueue实例被释放为止。由于目标-C侧队列是一个单例,它在应用程序的生命周期内不会被释放。

RoboVM NSOperationQueue类提供了接受RunnableaddOperation()方法的一个版本。在使用此方法时,RoboVM将负责保留Runnable实例,而目标-C端则需要它。对于任何接受@Block注解参数类型的Runnable或任何org.robovm.objc.block.VoidBlock*org.robovm.objc.block.Block*接口的方法,也是如此。

使用这个addOperation()方法,您的代码就变成了:

代码语言:javascript
复制
public static void runOnUiThread(Runnable runnable) {
    NSOperationQueue.getMainQueue().addOperation(runnable);      
}

PS。RoboVM使用的GC与苹果垃圾收集器无关,因此苹果的文档不会帮助您理解这样的问题。

票数 1
EN

Stack Overflow用户

发布于 2015-06-07 01:19:37

好吧..。这就解决了以下问题:

代码语言:javascript
复制
public static void runOnUiThread(final Runnable runnable) {

    final NSOperationQueue mainQueue = NSOperationQueue.getMainQueue();

    NSOperation operation = new NSOperation() {

        @Override
        public void main() {
            runnable.run();

            mainQueue.removeStrongRef(runnable);
            mainQueue.removeStrongRef(this    );
        }
    };

    mainQueue.addStrongRef(runnable );
    mainQueue.addStrongRef(operation);

    mainQueue.addOperation(operation);      
}

但别问我为什么要这么做。Apple是这么说的,正如我之前尝试的那样,“在垃圾收集应用程序中,队列强烈引用操作对象。”operation.addStrongRef(runnable);应该已经足够了,因为操作对象应该被队列引用。但是我想这个世界并不总是像我解释文档那样工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30688370

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档