Как запустить ProgressBar, используя данные из стороннего пакета

Рейтинг: -1Ответов: 1Опубликовано: 07.04.2023

Дано: Пакет, написанный на С# и прогнанный через генератор Java. Передан мне в виде папки с названием, которую я просто скопировал в проект. Там есть функция, которая вызывается например так:

AlgoResult res = processAlgorithm(portf, apars, _ProgressChangedEventHandler_ _progress);

Функция очень тяжелая, устройство виснет секунд на 30-40 (можно и сильно больше, если постараться ), она основная в Приложении, поэтому хочется приделать к ней хотя бы ProgressBar.

Последний аргумент - как раз для бегунка.

Инструкция от разработчика:

В класс нужно добавить следующее (прямо внутрь, где эта функция), только в строке

public static Program _globalInstance;

изменить Program на имя своего класса. Основная реализация - после строки: // здесь вывод бегунка

    private static void _progress(Object sender, ProgressEventArgs arg) {
                // здесь вывод бегунка
                
            }
        
    public static class ProgressChangedEventHandler_ _progress implements 
          ProgressEventHandler {
            
                @Override
                public void call(Object sender, ProgressEventArgs arg) {
                    _progress(sender, arg);
                }
                public ProgressChangedEventHandler_ _progress() {
                }
            }
        
private static ProgressChangedEventHandler_ _progress 
        _ProgressChangedEventHandler_ _progress;
            public static Program _globalInstance;
            
            static {
                try { _globalInstance = new Program(); } 
                catch(Exception e) { }
                _ProgressChangedEventHandler_ _progress = new 
                ProgressChangedEventHandler_ _progress();
            }

Поскольку вызов функции у меня прямо из Main, то, как и написано, поменял Program на MainActivity и добавил "вывод бегунка" в логи:

public static MainActivity _globalInstance;
        
            static {
                try { _globalInstance = new MainActivity(); }
                catch(Exception e) { }
                _ProgressChangedEventHandler__progress = new ProgressChangedEventHandler__progress();
            }
    
private static void _progress(Object sender, ProgressEventArgs arg) {
                    // здесь вывод бегунка
                    percentProgress = arg.getProgressPercentage();          
                    Log.d(TAG, percentProgress + "% ");
                }

Реально, в логи валятся цифры от 1 до 100.

И с этого момента случился затык. Перебрал кучу вариантов реализации прогресс бара, найденных в разных местах, но получил один из двух исходов:

  1. Всё умирает на 30 секунд, прогресс появляется сразу 100% одновременно с результатом;
  2. Прогресс бежит на фоне сообщения о неудачном исходе вычислений (UI отработал независимо на пустом результате) и если продолжать, то следующий прогресс бежит уже на фоне результата предыдущего вычисления и т.д.;

Коды выкладывать не буду, чтобы не позориться ). Да они и не сохранились. Разработчик предлагает найти в jave аналог сишного doEvents и не парить ему мозги со всякой ерундой (претензий нет, пакет написан в качестве шефской помощи и человек никогда не писал для мобильных устройств вообще и на jave, в частности).

Предложите, пожалуйста, вариант реализации. Спасибо.

PS:

Испробованные варианты:

Исход 1:

(Прямо по инструкции )

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
...

int percentProgress;
ProgressBar progressAlgorithm;
...

private static void _progress(Object sender, ProgressEventArgs arg) {
        // здесь вывод бегунка
        percentProgress = arg.getProgressPercentage();
        progressAlgorithm.setProgress(percentProgress);      
}

...

 @Override
    public void onClick(View v)
    {
        switch(v.getId())
        {
          ...
          case R.id.chCalculation:
                    algoResult = processAlgorithm(port, algoParams,_ProgressChangedEventHandler_ _progress);
           break;
          ...
         }
     }
...

}

Исход 2:

.....
     @Override
            public void onClick(View v)
            {
                switch(v.getId())
                {
                  ...
                  case R.id.chCalculation:
                   Thread threadGetResult = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try
                        {
                            algoResult = processAlgorithm(port,                              
                       algoParams,_ProgressChangedEventHandler_ _progress);
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                });
                threadGetResult.start();
                            
                   break;
                  ...
                 }
             }
    .....

Это то, что сразу сделал. Дальше были попытки

threadGetResult.join();

Получился Исход 1

Потом пробовал усыплять основной поток на полсекунды внутри onClick, когда функция в фоновом потоке. Получился Исход 1.

while (percentProgress < 99)`
{
    progressAlgoruthm.setProgress(percentProgress);
    try {
         Thread.sleep(500);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

Еще что-то делал, сейчас и не вспомню уже. И вроде как понятно, что происходит, но непонятно, как это обойти )

И да, private static void _progress работает, как автомат Калашникова - числа прогресса во всех вариантах валятся в логи со страшной силой )

Ответы

▲ 0Принят

Все у вас почти правильно:

private void startCalc() {
    new Thread(()->{
        AlgoResult algoResult = processAlgorithm(port, algoParams, (sender, arg) -> {
            runOnUiThread(() -> showProgress(arg.getProgressPercentage()));
        });
        runOnUiThread(() -> showResult(algoResult));
    }).start();
}

private void showProgress(int progress){
    progressBar.setProgress(progress);
}

private void showResult(AlgoResult result){
    Toast.makeText(this, "calc result is...", Toast.LENGTH_SHORT).show();
}

NB Но вообще так не принято писать. И Thread и в колбэке обращение к ui...
Юзер может свернуть или закрыть приложение или просто повернуть экран, а поток попытается прожить дольше, чем progressBar и все упадет. Тут можно через foreground сервис с уведомлением прогресса и workmanager с тем же уведомлением если надо. Если результат вычисления важен пользователю (всякое бывает), его неплохо бы сохранить, а когда посчитается, показать или в следующий раз когда откроет приложение...

ЗЫ Лямбды, надеюсь, не должны испугать.
ЗЗЫ Main Executor получается через Handler с MainLooper'ом.