2015-06-06 65 views
0

如果我撥打以下RoboVM方法與任何非空說法真是奇怪的NullPointerException在RoboVM

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) 

這到底是怎麼回事???更重要的是,我該如何解決它?

  • 我試過在NSOperationQueue...之前加operation.addStrongRef(runnable);。沒有不同。
  • 我也嘗試將匿名內部類移動到它自己的類中,它有一個private final字段來存儲傳遞給它的構造函數的runnable。同樣的結果。

我只是想念一些完全明顯的東西?

回答

1

你說得對。您的NSOperation實例在從Objective-C端調用操作之前進行垃圾收集。當NSOperationQueue調用Java端時,將創建一個匿名類的新實例,該實例沒有對Runnable實例的引用,而是null,結果是引發了NullPointerException

你解決它使用addStrongRef()的方式是正確的,雖然只有mainQueue.addStrongRef(operation)和相應的removeStrongRef()調用應該是足夠了:

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實例(以及任何Java對象到達從它像Runnable)被GCed直到Objective-C NSOperationQueue實例被解除分配。由於Objective-C隊列是一個單例,它在應用程序的生命週期中不會被釋放。

RoboVM NSOperationQueue Java類提供了addOperation()方法的一個版本,其中需要Runnable。當使用這種方法時,RoboVM將負責保留Runnable實例,同時Objective-C爲您需要它。任何採用類型的@Block註釋參數或任何org.robovm.objc.block.VoidBlock*org.robovm.objc.block.Block*接口的方法也是如此。

使用這種方法addOperation()你的代碼可以簡化爲:

public static void runOnUiThread(Runnable runnable) { 
    NSOperationQueue.getMainQueue().addOperation(runnable);  
} 

PS。 RoboVM使用的GC與Apple垃圾收集器無關,因此Apple的文檔無法幫助您理解這樣的問題。

+0

這很有道理。謝謝。 +1 addOperation(Runnable)'。我完全錯過了!順便說一句:RoboVM絕對是驚人的!我很高興我不必處理Objective-C(yuck!)!你們真棒!非常感謝!我的生命中最美好的一天將是有RoboVM版本,可以爲Windows Phone構建應用程序! ;)考慮到你已經擁有的基礎設施,這會很難嗎?或者你已經在研究它了? :) –

+0

我很高興聽到你喜歡RoboVM!不,我們不支持Windows Phone。 MS最近宣佈將把Android應用帶到Windows Phone的[Project Astoria](https://dev.windows.com/en-us/uwp-bridges/project-astoria)。一旦無法將RoboVM移植到Windows Phone就沒有多大意義。雖然...會是一個有趣的挑戰:-) – ntherning

0

嗯......這修復它:

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

但不要問我爲什麼,這是必要的。蘋果文檔說"In garbage-collected applications, the queue strongly references the operation object."因此,我早些時候嘗試過的operation.addStrongRef(runnable);應該已經足夠,因爲操作對象應該由隊列引用。但我想這個世界並不總是按我解釋文檔的方式工作。