代码之家  ›  专栏  ›  技术社区  ›  Maksym Gontar

黑莓-加载/等待动画屏幕

  •  13
  • Maksym Gontar  · 技术社区  · 17 年前

    有显示“正在加载”屏幕的方法吗 用动画 在黑莓?

    选项:

    • PME动画内容
    • 多线程+图像集+计时器/计数器
    • 标准RIM API
    • 其他方式

    有这些吗?

    谢谢!

    7 回复  |  直到 14 年前
        1
  •  35
  •   Maksym Gontar    16 年前

    费明,安东尼+1.谢谢大家,你给了我部分答案。
    我的最终解决方案:

    1.创建或生成( free Ajax loading gif generator )动画并将其添加到项目中。

    2.创建ResponseCallback接口(参见 Coderholic - Blackberry WebBitmapField )接收线程执行结果:

    public interface ResponseCallback {
        public void callback(String data);  
    }
    

    3.创建一个类来处理后台线程作业。在我的例子中,是HTTP请求:

    public class HttpConnector 
    {
      static public void HttpGetStream(final String fileToGet,
        final ResponseCallback msgs) {
        Thread t = new Thread(new Runnable() {
          public void run() {
            HttpConnection hc = null;
        DataInputStream din = null;
        try {
          hc = (HttpConnection) Connector.open("http://" + fileToGet);
          hc.setRequestMethod(HttpsConnection.GET);
          din = hc.openDataInputStream();
          ByteVector bv = new ByteVector();
          int i = din.read();
          while (-1 != i) {
            bv.addElement((byte) i);
            i = din.read();
          }
          final String response = new String(bv.toArray(), "UTF-8");
          UiApplication.getUiApplication().invokeLater(
            new Runnable() {
              public void run() {
            msgs.callback(response);
                  }
                });
        } 
            catch (final Exception e) {
              UiApplication.getUiApplication().invokeLater(
                new Runnable() {
                  public void run() {
                    msgs.callback("Exception (" + e.getClass() + "): " 
                      + e.getMessage());
                  }
                });
            } 
            finally {
              try {
                din.close();
                din = null;
                hc.close();
                hc = null;
              }
              catch (Exception e) {
              }
            }
          }
        });
      t.start();
      }
    }
    

    4.创建waitscreen(全屏和 AnimatedGIFField 带ResponseCallback接口):

    public class WaitScreen extends FullScreen implements ResponseCallback 
    {
        StartScreen startScreen;
        private GIFEncodedImage _image;
        private int _currentFrame;
        private int _width, _height, _xPos, _yPos;
        private AnimatorThread _animatorThread;
        public WaitScreen(StartScreen startScreen) {
            super(new VerticalFieldManager(), Field.NON_FOCUSABLE);
            setBackground(
                BackgroundFactory.createSolidTransparentBackground(
                    Color.WHITE, 100));
            this.startScreen = startScreen;
            EncodedImage encImg = 
              GIFEncodedImage.getEncodedImageResource("ajax-loader.gif");
            GIFEncodedImage img = (GIFEncodedImage) encImg;
    
            // Store the image and it's dimensions.
            _image = img;
            _width = img.getWidth();
            _height = img.getHeight();
            _xPos = (Display.getWidth() - _width) >> 1;
            _yPos = (Display.getHeight() - _height) >> 1;
            // Start the animation thread.
            _animatorThread = new AnimatorThread(this);
            _animatorThread.start();
            UiApplication.getUiApplication().pushScreen(this);
        }
    
        protected void paint(Graphics graphics) {
            super.paint(graphics);
                // Draw the animation frame.
                graphics
                  .drawImage(_xPos, _yPos, _image
                    .getFrameWidth(_currentFrame), _image
                      .getFrameHeight(_currentFrame), _image,
                    _currentFrame, 0, 0);
        }
    
        protected void onUndisplay() {
            _animatorThread.stop();
        }
    
        private class AnimatorThread extends Thread {
            private WaitScreen _theField;
            private boolean _keepGoing = true;
            private int _totalFrames, _loopCount, _totalLoops;
            public AnimatorThread(WaitScreen _theScreen) {
                _theField = _theScreen;
                _totalFrames = _image.getFrameCount();
                _totalLoops = _image.getIterations();
    
            }
    
            public synchronized void stop() {
                _keepGoing = false;
            }
    
            public void run() {
                while (_keepGoing) {
                    // Invalidate the field so that it is redrawn.
                    UiApplication.getUiApplication().invokeAndWait(
                      new Runnable() {
                        public void run() {
                            _theField.invalidate();
                        }
                    });
                    try {
                      // Sleep for the current frame delay before
                      // the next frame is drawn.
                      sleep(_image.getFrameDelay(_currentFrame) * 10);
                    } catch (InterruptedException iex) {
                    } // Couldn't sleep.
                    // Increment the frame.
                    ++_currentFrame;
                    if (_currentFrame == _totalFrames) {
                      // Reset back to frame 0 
                      // if we have reached the end.
                      _currentFrame = 0;
                      ++_loopCount;
                      // Check if the animation should continue.
                      if (_loopCount == _totalLoops) {
                        _keepGoing = false;
                      }
                    }
                }
            }
    
        }
    
        public void callback(String data) {
            startScreen.updateScreen(data);
            UiApplication.getUiApplication().popScreen(this);
        }
    }
    

    5.最后,创建开始屏幕调用httpconnector.httpgetstream并显示waitscreen:

    public class StartScreen extends MainScreen
    {
        public RichTextField text;
        WaitScreen msgs;
        public StartScreen() {       
            text = new RichTextField();
            this.add(text);
        }
    
        protected void makeMenu(Menu menu, int instance) {
            menu.add(runWait);
            super.makeMenu(menu, instance);
        }
    
        MenuItem runWait = new MenuItem("wait", 1, 1) {
            public void run() {
                UiApplication.getUiApplication().invokeLater(
                    new Runnable() {
                        public void run() {
                            getFile();
                        }
                });             
            }
        };
    
        public void getFile() {
            msgs = new WaitScreen(this);
            HttpConnector.HttpGetStream(
                "stackoverflow.com/faq", msgs);                 
        }
    
        //you should implement this method to use callback data on the screen.
        public void updateScreen(String data)
        {
            text.setText(data);
        }
    }
    

    更新: 另一个解决方案 naviina.eu: A Web2.0/Ajax-style loading popup in a native BlackBerry application

        2
  •  4
  •   Anthony Rizk    17 年前

    这种情况的基本模式是:

    让一个线程运行一个循环,该循环更新一个变量(例如动画图像的帧索引),然后在绘制图像的字段上调用invalidate(无效),然后休眠一段时间。无效将对字段的重新绘制进行排队。

    在字段的绘制方法中,读取变量并绘制适当的图像帧。

    伪代码(不是完全完整的,但为了给你一个想法):

    public class AnimatedImageField extends Field implements Runnable {
    
       private int currentFrame;
       private Bitmap[] animationFrames;
    
       public void run() {
         while(true) {
           currentFrame = (currentFrame + 1) % animationFrames.length;
           invalidate();
           Thread.sleep(100);
          }
        }
    
       protected void paint(Graphics g) {
          g.drawBitmap(0, 0, imageWidth, imageHeight, animationFrames[currentFrame], 0, 0);
        }
      }
    

    注意这里我还使用了一组位图,但是EncodeDimage允许您将动画GIF视为一个对象,并且包括获取特定帧的方法。

    编辑:为了完整性:将其添加到弹出屏幕(如fermin的答案)或直接覆盖屏幕创建您自己的对话框。独立线程是必需的,因为RIM API不是线程安全的:您需要在事件线程上执行所有与UI相关的操作(或者在保持事件锁的同时,请参见 BlackBerry UI Threading - The Very Basics

        3
  •  4
  •   Dhiral Pandya    14 年前

    这是加载屏幕的简单代码….

                    HorizontalFieldManager popHF = new HorizontalFieldManager();
                    popHF.add(new CustomLabelField("Pls wait..."));
                    final PopupScreen waitScreen = new PopupScreen(popHF);
                    new Thread()
                    {
                        public void run() 
                        {
    
                            synchronized (UiApplication.getEventLock()) 
                            {
                                UiApplication.getUiApplication().pushScreen(waitScreen);
                            }
                           //Here Some Network Call 
    
                           synchronized (UiApplication.getEventLock()) 
                            {
                                UiApplication.getUiApplication().popScreen(waitScreen);
                            }
                         }
                     }.start();
    
        4
  •  3
  •   Fermin    17 年前

    如果只是一个动画,你能展示一个 animated gif 在弹出窗口上,并在加载操作完成时关闭它?

        5
  •  2
  •   Fermin    17 年前

    最简单的方法可能是使用标准GaugeField,设置样式GaugeField.Percent。这会给你一个进度条。将此添加到弹出屏幕,它将位于内容的顶部。比如……

    private GaugeField _gaugeField;
    private PopupScreen _popup;
    
    public ProgressBar() {    
        DialogFieldManager manager = new DialogFieldManager();
        _popup = new PopupScreen(manager);
        _gaugeField = new GaugeField(null, 0, 100, 0, GaugeField.PERCENT);    
        manager.addCustomField(_gaugeField);
    }
    

    然后有一个更新方法,它将使用_GaugeField.setValue(newValue);来更新进度条。

    我通常从执行工作的线程调用这个(在您的例子中,每次操作完成时,都会更新进度条)。

        6
  •  2
  •   Sameer    16 年前

    我建议看一下这个简单的实现。我喜欢这个,但从未用过。可能对你有帮助。

    link text