Модераторы: javastic, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Отображение статуса выполнения операции, Не обновляется окно со статусом 
:(
    Опции темы
FiMa1
  Дата 2.4.2011, 21:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 408
Регистрация: 23.9.2006

Репутация: нет
Всего: 6



Ребята, привет всем!

Кто-нибудь имеет рабочие реализации окна с отображением статуса выполнения некой операции? Я никак не могу добиться рабочего варианта. Мои варианты приведены ниже. Понимаю, много кода и разбираться скорее всего не захочется, интересуют ваши рабочие решения, если не жаль поделиться =)

Первый вариант. В данном варианте кроме главного создается еще один поток для выполнения необходимой работы в фоне (в классе Executor). Класс Executor периодически обновляет (продвигает) отображение статуса, за которое отвечает класс StatusScreen. В целом это вполне рабочий вариант, однако есть проблема - главный поток продолжает выполнение, т.е фраза "Completed!" будет отображена за долго до окончания работы потока класса Executor. Выполнить join() для этого фонового потока Executor нельзя, т.к. вешается работа программы в принципе. Я так понимаю это из-за того, что repaint(), вызываемый в StatusScreen.updateStatus() как-то кооперирует с главным потоком, точно не знаю...

main.Main.java
Код

package main;

import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

/**
 * Entry point of the midlet
 */
public class Main extends MIDlet {
    public static Main midlet;
    public static Display display;
    Executor executor;

    public Main() throws InterruptedException {
        midlet = this;
        display = Display.getDisplay(this);        
    }

    protected void destroyApp(boolean unconditional)
            throws MIDletStateChangeException {
        notifyDestroyed();
    }

    protected void pauseApp() {
    }

    protected void startApp() throws MIDletStateChangeException {
        new StatusScreen().show();
        System.out.println("Completed!");
    }
}

main.StatusScreen.java
Код

package main;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.midlet.MIDletStateChangeException;

/**
 * StatusScreen class shows progress status of some processing 
 */
public class StatusScreen extends Canvas implements CommandListener {
    private Command exit;
    private Thread executorThread;
    int status;

    public StatusScreen() {
        exit = new Command("Exit", Command.EXIT, 1);
        addCommand(exit);
        setCommandListener(this);
    }

    protected void paint(Graphics g) {
        System.out.println("GraphicStatusView.paint");
        // clear the screen
        g.setColor(255, 255, 255);
        g.fillRect(0, 0, getWidth(), getHeight());

        // set the pen to black
        g.setColor(0, 0, 0);

        // paint the processing progress status
        g.drawString("Processing: " + status + "%", getWidth() / 2,
                getHeight() / 2, Graphics.HCENTER | Graphics.TOP);

        if (executorThread == null) {
            executorThread = new Thread(new Executor(this));
            executorThread.start();
        }

        System.out.println("GraphicStatusView.paint.end");
    }

    public void updateStatus(int status) {
        this.status = status;
        repaint();
    }

    public void show() {
        Main.display.setCurrent(this);
    }

    public void commandAction(Command c, Displayable d) {
        if (c == exit) {
            try {
                Main.midlet.destroyApp(true);
            } catch (MIDletStateChangeException e) {
            }
        }
    }
}

main.Executor.java
Код

package main;

/**
 * Executor class performs some work
 */
public class Executor implements Runnable {
    StatusScreen screen;
    
    public Executor(StatusScreen screen) {
        this.screen = screen;
    } 

    public void run() {
        System.out.println("Executor.run");
        // emulate some processing
        for (int i = 1; i <= 100; i++) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // IF counter equals to progress step
            if (i % 10 == 0) {
                screen.updateStatus(i);
            }
        }
        System.out.println("Executor.run.end");
    }
}

Консольный вывод первого варианта мидлета:
Код

GraphicStatusView.paint
GraphicStatusView.paint.end
Completed! <- Вот оно! Главный поток продолжает работу
Executor.run
GraphicStatusView.paint
GraphicStatusView.paint.end
GraphicStatusView.paint
GraphicStatusView.paint.end
GraphicStatusView.paint
GraphicStatusView.paint.end
GraphicStatusView.paint
GraphicStatusView.paint.end
GraphicStatusView.paint
GraphicStatusView.paint.end
GraphicStatusView.paint
GraphicStatusView.paint.end
GraphicStatusView.paint
GraphicStatusView.paint.end
GraphicStatusView.paint
GraphicStatusView.paint.end
GraphicStatusView.paint
GraphicStatusView.paint.end
Executor.run.end
GraphicStatusView.paint
GraphicStatusView.paint.end

Второй вариант. В этом варианте добавлен новый класс - Progress. Этот класс предоставляет методы extendProgress и getStatus. Первый - для "продвижения" статуса, второй для его получения. Два других класса - Executor (выполнение работы) и StatusScreen делят между собой  объект типа Progress, обмениваясь через него информацией о текущем состоянии (статусе) выполнения работы.

Поскольку работа и отображение выполняются в отдельных потоках, есть возможность использования join для временной приостановки работы основного потока, однако есть другая проблема - выполняется отображение только начального и финального состояний выполнения операций (0% и 100%) поскольку все промежуточные вызовы Status.updateStatus (и, соответственно, repaint) игнорируются (откладываются) виртуальной машиной, т.к., известно, repaint - это только просьба отрисовать что-то на экране (аналогично вызову сборщика мусора), этот просьба может проигнорирована java машиной в случае ее загрузки другими процессами.

Пробовал вставлять serviceRepaints после repaint - безрезультатно.

main.Main.java
Код

package main;

import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

/**
 * Entry point of the midlet
 */
public class Main extends MIDlet {
    public static Main midlet;
    public static Display display;
    Executor executor;

    public Main() throws InterruptedException {
        midlet = this;
        display = Display.getDisplay(this);        
    }

    protected void destroyApp(boolean unconditional)
            throws MIDletStateChangeException {
        notifyDestroyed();
    }

    protected void pauseApp() {
    }

    protected void startApp() throws MIDletStateChangeException {
        int progressStep = 10;
        Progress progress = new Progress(progressStep);        
        new StatusScreen(progress).show();
        System.out.println("Completed!");
    }
}

main.Executor.java
Код

package main;

public class Executor implements Runnable {
    private Progress progress;
    
    public Executor(Progress progress) {
        this.progress = progress;
    } 

    public void run() {
        System.out.println("Executor.run");
        // emulate some processing
        for (int i = 1; i <= 100; i++) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // IF counter equals to progress step
            if (i % 10 == 0) {
                progress.extendProgress();
            }
        }
        System.out.println("Executor.run.end");
    }
}

main.StatusScreen.java
Код

package main;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.midlet.MIDletStateChangeException;

/**
 * StatusScreen class shows progress status of some processing 
 */
public class StatusScreen extends Canvas implements CommandListener, Runnable {
    private int status;
    private Command exit;
    private Thread executorThread;
    private Thread statusUpdateThread;
    private Progress progress;

    public StatusScreen(Progress progress) {
        this.progress = progress;
        statusUpdateThread = new Thread(this);
        exit = new Command("Exit", Command.EXIT, 1);
        addCommand(exit);
        setCommandListener(this);
    }

    protected void paint(Graphics g) {
        System.out.println("StatusScreen.paint");
        // clear the screen
        g.setColor(255, 255, 255);
        g.fillRect(0, 0, getWidth(), getHeight());

        // set the pen to black
        g.setColor(0, 0, 0);

        // paint the processing progress status
        g.drawString("Processing: " + status + "%", getWidth() / 2,
                getHeight() / 2, Graphics.HCENTER | Graphics.TOP);

        if (executorThread == null) {
            executorThread = new Thread(new Executor(progress));
            executorThread.start();
            try {
                // suspend main thread until the processing is completed
                statusUpdateThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("StatusScreen.paint.end");
    }

    public void updateStatus(int status) {
        this.status = status;
        repaint();
    }

    public void show() {
        statusUpdateThread.start();
        Main.display.setCurrent(this);
    }

    public void commandAction(Command c, Displayable d) {
        if (c == exit) {
            try {
                Main.midlet.destroyApp(true);
            } catch (MIDletStateChangeException e) {
            }
        }
    }

    public void run() {
        int status;
        while ((status = progress.getStatus()) < Progress.UPPER_LIMIT) {
            updateStatus(status);
        }
        updateStatus(Progress.UPPER_LIMIT);
    }
}

main.Progress
Код

package main;

/**
 * This class describes progress for some processing
 */
public class Progress {
    private int status;
    private boolean isProgressExtended = false;
    static final int UPPER_LIMIT = 100; // 100%
    int progressStep;

    /**
     * @param step
     *            Defines a step for extending progress status (1-50%)
     */
    public Progress(int step) {
        progressStep = step;
    }

    /**
     * Extends progress to progress step
     */
    public synchronized void extendProgress() {
        System.out.println("Progress.extendProgress");
        if (isProgressExtended) {
            try {
                wait(); // wait until progress is repainted
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        status += progressStep;
        isProgressExtended = true;
        
        System.out.println("Progress.extendProgress.end");
        
        notify();
    }

    /**
     * @return Current progress status
     */
    public synchronized int getStatus() {
        System.out.println("Progress.getStatus");
        if (!isProgressExtended) {
            try {
                wait(); // wait until progress is extended
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isProgressExtended = false;
        
        System.out.println("Progress.getStatus.end");
        
        notify();
        return status;
    }

    public int getProgressStep() {
        return progressStep;
    }
}

Консольный вывод второго варианта мидлета:
Код

StatusScreen.paint <- Вывели состояние статуса 0% и начали работу
Progress.getStatus
Executor.run
Progress.extendProgress
Progress.extendProgress.end
Progress.getStatus.end
Progress.getStatus
Progress.extendProgress
Progress.extendProgress.end
Progress.getStatus.end
Progress.getStatus
Progress.extendProgress
Progress.extendProgress.end
Progress.getStatus.end
Progress.getStatus
Progress.extendProgress
Progress.extendProgress.end
Progress.getStatus.end
Progress.getStatus
Progress.extendProgress
Progress.extendProgress.end
Progress.getStatus.end
Progress.getStatus
Progress.extendProgress
Progress.extendProgress.end
Progress.getStatus.end
Progress.getStatus
Progress.extendProgress
Progress.extendProgress.end
Progress.getStatus.end
Progress.getStatus
Progress.extendProgress
Progress.extendProgress.end
Progress.getStatus.end
Progress.getStatus
Progress.extendProgress
Progress.extendProgress.end
Progress.getStatus.end
Progress.getStatus
Progress.extendProgress
Progress.extendProgress.end
Executor.run.end
Progress.getStatus.end
StatusScreen.paint.end <- Убрали состояние статуса 0%
Completed!
StatusScreen.paint  <- Отобразили состояние статуса 100%
StatusScreen.paint.end <- Убрали отображение состояния статуса 100%

Смежная информация (для последователей):

Это сообщение отредактировал(а) FiMa1 - 2.4.2011, 22:24
PM   Вверх
FiMa1
Дата 2.4.2011, 23:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 408
Регистрация: 23.9.2006

Репутация: нет
Всего: 6



Пока ничего умней, чем ввести public static boolean isProcessingCompleted; для первого способа в классе Main (главный поток) не придумал. Соответственно, выставляю isProcessingCompleted в true в Executor.run после завершения основной работы. Ну или можно в главном потоке мониторить isAlive() для потока выполнения работы.

В любом случае способ оказался нерабочим, работает только в приведенном выше примитивном контексте. После интеграции в проект ничего не заработало и дело не в ошибочной интеграции. В проекте инициализация приведенных выше классов и отображение StatusScreen выполняется не из startApp() мидлета, а из некоего вторичного класса, в таком случае главная нитка даже и не пытается зайти в StatusScreen.paint() после вызова StatusScreen.show(), соответственно поток для выполнения работы не запускается и главная нитка навсегда падает в бесконечный цикл, ожидая там isProcessingCompleted = true. Фоновая работа - инициализация трех RMS, в одной из которых ~300 записей.

Вопрос о действительно рабочих вариантах означенной задачи для меня всё ещё открыт =)

Это сообщение отредактировал(а) FiMa1 - 3.4.2011, 14:37
PM   Вверх
PiyodaiSiyo
Дата 4.4.2011, 01:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 112
Регистрация: 31.12.2009

Репутация: 1
Всего: 2



рассмотрел 1 вариант, главный поток(мидлет вход startapp) создает обьект StatusScreen а  и вызывает его метод show()который ставит того в дисплэй, запускается прослушка событий и первая отрисовка  (обьект ведь канвас) неявно(!) метода  пэинт (display.setCurrent для этого ) который ..ну и т.д.
а главный закончив с шоу() продолжает следующую директиву т.е. выводит  "Completed!".если вставить перед system.out.println цикл с какой нибудь глобальной лог. переменной то надпись выйдет после окончания всех потоков, а в чем собственно вопрос ?
А если экз. StatusScreen создается в экз.др класса  то пропишите в конструкторе StatusScreen() в конце repaint(); и без display зачем он нужен?

Да... Просмотрел в sdk3 все нормально как и в приведенном вами окне output а
PM MAIL   Вверх
FiMa1
  Дата 4.4.2011, 09:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 408
Регистрация: 23.9.2006

Репутация: нет
Всего: 6



Цитата

рассмотрел 1 вариант, главный поток(мидлет вход startapp) создает обьект StatusScreen а  и вызывает его метод show()который ставит того в дисплэй, запускается прослушка событий и первая отрисовка  (обьект ведь канвас) неявно(!) метода  пэинт (display.setCurrent для этого ) который ..ну и т.д.
а главный закончив с шоу() продолжает следующую директиву т.е. выводит  "Completed!".если вставить перед system.out.println цикл с какой нибудь глобальной лог. переменной то надпись выйдет после окончания всех потоков, а в чем собственно вопрос ?

По этому пункту вопросов действительно нет, так как "вставить перед system.out.println цикл с какой нибудь глобальной лог. переменной" я уже предложил во втором своем посте (может быть туманно описал замысел):
Цитата

Пока ничего умней, чем ввести public static boolean isProcessingCompleted; для первого способа в классе Main (главный поток) не придумал. Соответственно, выставляю isProcessingCompleted в true в Executor.run после завершения основной работы. Ну или можно в главном потоке мониторить isAlive() для потока выполнения работы.
Код

protected void startApp() throws MIDletStateChangeException {
    new StatusScreen().show();
    while(!isProcessingCompleted) {
        ;
    }
    System.out.println("Completed!");
}


Что касается:
Цитата

А если экз. StatusScreen создается в экз.др класса  то пропишите в конструкторе StatusScreen() в конце repaint(); и без display зачем он нужен?

Да... Просмотрел в sdk3 все нормально как и в приведенном вами окне output а

Здесь смысл сказанного от меня ускользает... Что вы имели в виду?

Это сообщение отредактировал(а) FiMa1 - 4.4.2011, 09:13
PM   Вверх
FiMa1
  Дата 4.4.2011, 21:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 408
Регистрация: 23.9.2006

Репутация: нет
Всего: 6



Пока удалено ибо написал неправильно. Думаю...

Это сообщение отредактировал(а) FiMa1 - 4.4.2011, 21:53
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса

  • Прежде чем задать вопрос прочтите это!
  • Литература по Java находится здесь.
  • Литературу по Java обсуждаем здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит" (возле кнопок кодов) если у Вас нет русских шрифтов.
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда

  • FAQ раздела лежит здесь!
 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java ME (J2ME) | Следующая тема »


 




[ Время генерации скрипта: 0.0762 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.