ios - 代号一中的 BackgroundFetch

标签 ios codenameone

我正在为 iOS 开发一个代号 One 应用程序,我正在尝试使用 BackgroundFetch 接口(interface)。

我复制了用 Javadoc ( https://www.codenameone.com/javadoc/com/codename1/background/BackgroundFetch.html ) 编写的示例代码,并添加了 ios.background_modes=fetch 构建提示。

在模拟器上启动应用程序,后台操作正确执行。

在真实设备(iPhone 7s、iOs 12.1.4)上启动它,行为是不可预测的。尽管设置了 setPreferredBackgroundFetchInterval(10),但我注意到几乎每次启动应用程序时,后台操作都不会执行。很少执行后台操作,但应用程序必须在后台运行几分钟才能恢复它,而不是通过 setPreferredBackgroundFetchInterval(10) 方法设置的 10 秒。

Display.isBackgroundFetchSupported() 方法返回 true。

如果负担得起且可预测,我不明白如何制作。


编辑

我修改了示例代码,仅在 performBackgroundFetch() 实现中(Display.setPreferredBackgroundFetchInterval(10) 未更改)。我只是在标签中放了一些文字:

@Override
public void performBackgroundFetch(long deadline, Callback<Boolean> onComplete) {
    supported.setText("deadline: " + deadline + "; timeMillis: " + System.currentTimeMillis());
    onComplete.onSucess(Boolean.TRUE);
}

我观察到模拟器和真实设备的两种不同行为。 在模拟器中,该方法在进入暂停状态后恰好 10 秒执行。在真实设备中,该方法在进入暂停状态后 10 秒不会执行:在某些情况下,它会在 20 分钟后执行(在其他情况下,它根本不会执行)。 但是,在这两种情况下,我都可以计算截止日期与方法执行时间之间的差异:始终为 25 分钟。

例如,您可以看到应用程序的以下屏幕截图(在 iPhone 上运行):

截止日期 = 1560246881647 时间戳 = 1560245381647

截止日期 - 时间戳 = 1500000 毫秒 = 1500 秒 = 25 分钟。

据我了解,在 iOS 上,执行后台提取的时间限制为 30 秒,否则操作系统将终止该应用程序。此外,Display.setPreferredBackgroundFetchInterval() 用于设置后台获取之间的首选时间间隔,但不能保证,因为 iOS 保持对后台获取执行的控制。

后台抓取的正确使用方法是什么?

完整代码如下:

public class MyApplication implements BackgroundFetch{

   private Form current;
   private Resources theme;
   List<Map> records;
   Label supported;
   // Container to hold the list of records.
   Container recordsContainer;

   public void init(Object context) {
      theme = UIManager.initFirstTheme("/theme");

      // Enable Toolbar on all Forms by default
      Toolbar.setGlobalToolbar(true);

      // Pro only feature, uncomment if you have a pro subscription
      // Log.bindCrashProtection(true);
   }

   public void start() {
      if(current != null){
         // Make sure we update the records as we are coming in from the 
         // background.
         updateRecords();
         current.show();
         return;
      }
      Display d = Display.getInstance();

      // This call is necessary to initialize background fetch
      d.setPreferredBackgroundFetchInterval(10);

      Form hi = new Form("Background Fetch Demo");
      hi.setLayout(new BoxLayout(BoxLayout.Y_AXIS));

      supported = new Label();
      if (d.isBackgroundFetchSupported()){
         supported.setText("Background Fetch IS Supported");
      } else {
         supported.setText("Background Fetch is NOT Supported");
      }

      hi.addComponent(new Label("Records:"));
      recordsContainer = new Container(new BoxLayout(BoxLayout.Y_AXIS));
      //recordsContainer.setScrollableY(true);
      hi.addComponent(recordsContainer);
      hi.addComponent(supported);
      updateRecords();
      hi.show();
  }

  /**
   * Update the UI with the records that are currently loaded.
   */
  private void updateRecords() {
     recordsContainer.removeAll();
     if (records != null) {
        for (Map m : records) {
            recordsContainer.addComponent(new SpanLabel((String)m.get("title")));
        }
     } else {
        recordsContainer.addComponent(new SpanLabel("Put the app in the background, wait 10 seconds, then open it again.  The app should background fetch some data from the Slashdot RSS feed and show it here."));
     }
     if (Display.getInstance().getCurrent() != null) {
        Display.getInstance().getCurrent().revalidate();
     }
  }

  public void stop() {
     current = Display.getInstance().getCurrent();
     if(current instanceof Dialog) {
        ((Dialog)current).dispose();
        current = Display.getInstance().getCurrent();
     }
  }

  public void destroy() {
  }

  /**
   * This method will be called in the background by the platform.  It will
   * load the RSS feed.  Note:  This only runs when the app is in the background.
   * @param deadline
   * @param onComplete 
   */
  @Override
  public void performBackgroundFetch(long deadline, Callback<Boolean> onComplete) {
     supported.setText("deadline: " + deadline + "; timeMillis: " + System.currentTimeMillis());
     onComplete.onSucess(Boolean.TRUE);
  }

}

最佳答案

setPreferredBackgroundFetchInterval javadoc 声明:

Sets the preferred time interval between background fetches. This is only a preferred interval and is not guaranteed. Some platforms, like iOS, maintain sovereign control over when and if background fetches will be allowed. This number is used only as a guideline.

关于ios - 代号一中的 BackgroundFetch,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56526805/

相关文章:

ios - UIScrollView 内的 UITextView 不滚动 - Objective c

ios - 在 iOS 中解析 XML

forms - 如何禁用某些表单的后退按钮

java - CN1 中容器标签和按钮的大小/调整大小

ios - 使用异步编程在 TableView 上显示事件指示器 - Swift

ios - Apple Watch 滚动代码标签

ios - 在 iOS 中从 .xib 文件调用 UIViewController 时尝试传递 UIButton 的标记值

codenameone - 在 CN1 中的 JSON 中提取 JSON

java - 代号一工具栏高度

codenameone - 代号一如何设计倒置身份徽章