Blackberry - Экран загрузки / ожидания с анимацией - PullRequest
13 голосов
/ 29 апреля 2009

Есть ли способ показать экран "Загрузка" с анимацией в blackberry?

Опции:

  • анимационный контент PME
  • многопоточность + набор изображений + таймер / счетчик
  • стандартный обод api
  • как-то иначе

Что-нибудь из этого?

Спасибо!

Ответы [ 7 ]

35 голосов
/ 04 мая 2009

Фермин, Энтони +1. Спасибо всем, вы дали мне часть ответа.
Мое окончательное решение:

1.Создайте или сгенерируйте ( бесплатный 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.Создание экрана ожидания (гибрид FullScreen и 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: всплывающее окно загрузки в стиле Web2.0 / Ajax в собственном приложении BlackBerry

4 голосов
/ 27 сентября 2011

Это простой код для загрузки экрана ....

                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 голосов
/ 29 апреля 2009

Основной шаблон для такого рода вещей:

Иметь поток, выполняющий цикл, который обновляет переменную (например, индекс кадра анимированного изображения), а затем вызывает 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 как один объект и включает методы для получения определенных кадров.

РЕДАКТИРОВАТЬ: Для полноты: добавьте это в PopupScreen (как в ответе Фермина) или создайте свой собственный диалог, переопределяя Screen напрямую. Отдельный поток необходим, потому что API RIM не является поточно-ориентированным: вам нужно сделать все, что связано с пользовательским интерфейсом в потоке события (или, удерживая блокировку события, см. Потоки пользовательского интерфейса BlackBerry - основы

3 голосов
/ 29 апреля 2009

Если это просто анимация, не могли бы вы показать анимированный GIF во всплывающем окне и закрыть его после завершения операции загрузки?

2 голосов
/ 30 сентября 2009

Я бы предложил взглянуть на эту простую реализацию. Мне понравилось это, но никогда не использовал это. Может быть полезно для вас.

текст ссылки

2 голосов
/ 29 апреля 2009

Самым простым способом, вероятно, является использование стандартного GaugeField, установка стиля GaugeField.PERCENT. Это даст вам индикатор выполнения. Добавьте это к PopupScreen, и оно будет располагаться поверх вашего контента. Нечто подобное ..

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); обновить индикатор выполнения.

Обычно это вызывается из того, какой поток выполняет работу (загрузка в вашем случае, каждый раз, когда операция завершается, индикатор выполнения обновляется.

1 голос
/ 17 августа 2011

ActivityIndicator - хороший вариант, если вы работаете как минимум с BB OS 6.0.

http://www.brighthub.com/mobile/blackberry-platform/articles/94258.aspx

http://docs.blackberry.com/en/developers/deliverables/17966/Screen_APIs_1245069_11.jsp

...