Фоновый рендеринг и отображение пользовательского интерфейса - PullRequest
0 голосов
/ 29 октября 2018

Моя первая попытка на AndroidPlot. Данные, которые я хочу нанести на график (и обновлять каждые 5 секунд при получении новой точки данных), поступают с ArrayBlockingQueue до 720 временных отметок. У меня есть класс, который реализует интерфейсы XYSeries и PlotListener. У него есть метод updatePlotData, который просто извлекает данные из очереди в массив:

class TempPlotSeries implements XYSeries, PlotListener {
    private final static String TAG = TempPlotSeries.class.getSimpleName();
    private Pair<Date, Float>[] plotArray;
    void updatePlotData( ArrayBlockingQueue<Pair<Date, Float>> dataQueue ) throws InterruptedException {
        synchronized ( this ) {
            wait();       // don't update data until we're notified that current plot is done (& we can get lock)
            plotArray = dataQueue.toArray( new Pair[0] );
            if( DEBUG ) Log.d( TAG, "updatePlotData run with " + plotArray.length + " data points" );
            notifyAll();  // release lock & let other threads know they can continue
        }
    }

    // XYSeries implementation
    @Override
    public int size( ) {
        return plotArray.length;
    }
    @Override
    public Number getX( int index ) {
        return (index - HISTORY_BUFFER_SIZE) / (60/TEMP_UPDATE_SECONDS);  // e.g., -60 minutes at left edge of graph, -1/12 min at right
    }
    @Override
    public Number getY( int index ) {
        return plotArray[index].second;  // the temp value
    }
    @Override
    public String getTitle( ) {
        return "Temp History";
    }

    // PlotListener Implementation
    @Override
    public void onBeforeDraw( Plot source, Canvas canvas ) {
        synchronized ( this ) {
            try {
                wait();  // wait for data updating to finish if it's in progress on another thread
            } catch ( InterruptedException e ) {
                // unlikely to be interrupted?
            }
        }
    }
    // between these 2 calls the plot is redrawn
    @Override
    public void onAfterDraw( Plot source, Canvas canvas ) {
        synchronized ( this ) {
            notifyAll( );  // plot done, OK to update data
        }
    }
}

У меня нет большого опыта с синхронизацией - это выглядит разумно?

Моя настройка сюжета:

tempHistoryPlot = (XYPlot) findViewById(R.id.temp_history);
tempPlotSeries = new TempPlotSeries();
tempHistoryPlot.setRenderMode( Plot.RenderMode.USE_BACKGROUND_THREAD );
tempGraphFormatter = new LineAndPointFormatter(this, R.xml.line_point_formatter_with_labels);
tempHistoryPlot.addSeries(tempPlotSeries, tempGraphFormatter);
tempGraphWidget = tempHistoryPlot.getGraph();

(не удалось найти какую-либо документацию по цели getGraph(), поэтому не знаю, нужно ли мне это.)

У меня есть Observable (RxJava), который испускает всю очередь данных, когда доступен новый образец (каждые 5 секунд). Если очередь заполнена, я отбрасываю самое старое значение. Тогда у меня есть:

    tempPlotSeries.updatePlotData( newTempHistory );
    tempHistoryPlot.redraw();

Но сюжет не нарисован. Когда приложение запускается впервые, в его представлении появляется «фиктивный» график, но как только я пытаюсь нарисовать график, весь ConstraintLayout, содержащий элемент XYPlot (и другие элементы пользовательского интерфейса), полностью очищается. Что тут происходит?

Другие вопросы: я понимаю, что любой код, влияющий на пользовательский интерфейс Android, должен выполняться в основном потоке. Но мы используем фоновый поток для визуализации графика. Как это работает? Возможно, мне нужно вставить оператор .observeOn( AndroidSchedulers.mainThread() в мою цепочку наблюдаемых?

1 Ответ

0 голосов
/ 30 октября 2018

У меня нет большого опыта в синхронизации - это выглядит разумно?

Не думаю, что вам нужен wait() внутри синхронизированного блока внутри updatePlotData,Вы также можете использовать SimpleXYSeries в качестве справочной информации о том, как настроить синхронизацию такого рода.

Когда приложение запускается впервые, в его представлении появляется «фиктивный» график, но как только я пытаюсь нарисовать график, весь ConstraintLayout, содержащий элемент XYPlot (и другие элементы пользовательского интерфейса), полностьюгасятся.

У меня проблемы с визуализацией.Не могли бы вы добавить скриншот «фиктивного» графика и последующего пустого графика?

Насколько я понимаю, любой код, влияющий на пользовательский интерфейс Android, должен выполняться в основном потоке.Но мы используем фоновый поток для визуализации графика.Как это работает?

Общие правила использования основного потока для обновления пользовательского интерфейса все еще существуют, Androidplot просто использует технику для минимизации использования основного потока во время интенсивного рендеринга: используется фоновый потокзаполнить буфер растрового изображения данными, которые необходимо отобразить, а затем уведомить основной поток о готовности буфера к отображению.

Несколько не связанное предложение: глядя на вашу реализацию TempPlotSeries, я замечаю, что вы моделируетеваши данные как Pair<Date, Float>[], но ваша реализация getX() не использует часть Date.Похоже, вы пытаетесь смоделировать свои данные, используя то, что я предполагаю, является желаемым форматом отображения для вашего домена, т.е.От -60 до -1/12 минут.Для простоты я бы предложил сделать так, чтобы getX() возвращало значение длинной эпохи Даты.Вы можете применить формат отображения к этим значениям позже.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...