Проблема с рисованием динамического графика
Добавлено: 12 дек 2013, 14:21
Столкнулся с проблемой. Необходимо выводить на экран смартфона динамический график. Использую для этой цели Canvas и SurfaceView. Собственно проблема в том, что через 0.5 - 1 сек SurfaceView перестает рисовать поступившие данные.
WaveformPlotThread.java:
WaveformView.java:
Кусок MainActivity.java:
После запуска приложения примерно первые полсекунды SurfaceView рисует график как положено, затем отрисовка прекращается.
Соответственно Логи выглядят следующим образом:
Первые ~полсекунды:
Отправляем данные на отрисовку
Принимаем данные и обрабатываем
Обновляем экран
Отправляем данные на отрисовку
Принимаем данные и обрабатываем
Обновляем экран и т.д. ...
А затем:
Отправляем данные на отрисовку
Принимаем данные и обрабатываем
Отправляем данные на отрисовку
Принимаем данные и обрабатываем
Отправляем данные на отрисовку
Принимаем данные и обрабатываем ...
Я так понимаю, что SurfaceView через ~500 мсек просто перестает успевать рисовать. Помогите разобраться.
WaveformPlotThread.java:
Код: Выделить всё
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class WaveformPlotThread extends Thread {
private SurfaceHolder holder;
private WaveformView plot_area;
private boolean _run = false;
public WaveformPlotThread(SurfaceHolder surfaceHolder, WaveformView view){
holder = surfaceHolder;
plot_area = view;
}
public void setRunning(boolean run){
_run = run;
}
@Override
public void run(){
Canvas c;
while(_run){
c = null;
try{
c = holder.lockCanvas(null);
synchronized (holder) {
plot_area.PlotPoints(c);
}
}finally{
if(c!=null){
holder.unlockCanvasAndPost(c);
}
}
}
}
}Код: Выделить всё
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class WaveformView extends SurfaceView implements SurfaceHolder.Callback {
// Отладка
private static final String TAG = "WaveformView";
private static final boolean D = true;
private WaveformPlotThread plot_thread;
private final int width = 320;
private final int heigth = 240;
private final double Km = height/66000; // получаем Коэффициент масштаба
private static int[] ch1_data = new int[width];
private static int ch1_pos = 120;
private Paint ch1_color = new Paint();
private Paint grid_paint = new Paint();
private Paint cross_paint = new Paint();
private Paint outline_paint = new Paint();
public WaveformView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
int i;
for(i=0; i<width; i++){
ch1_data[i] = ch1_pos;
}
plot_thread = new WaveformPlotThread(getHolder(), this);
ch1_color.setColor(Color.rgb(66, 170, 255));
ch1_color.setStrokeWidth(5);
grid_paint.setColor(Color.rgb(100, 100, 100));
cross_paint.setColor(Color.rgb(70, 100, 70));
outline_paint.setColor(Color.GREEN);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
plot_thread.setRunning(true);
plot_thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
plot_thread.setRunning(false);
while (retry){
try{
plot_thread.join();
retry = false;
}catch(InterruptedException e){
}
}
}
@Override
public void onDraw(Canvas canvas){
PlotPoints(canvas);
}
public void set_data(int[] data){
int x;
if(D) Log.i(TAG, "Принимаем данные и обрабатываем");
plot_thread.setRunning(false);
x = 0;
while(x<width){
if(x<(data.length)){
if (data[x]>=0) {
ch1_data[x] = (int) (heigth/2 - data[x]*Km);
} else {
ch1_data[x] = (int) (heigth/2 + Math.abs(data[x])*Km);
}
} else{
ch1_data[x] = ch1_pos;
}
x++;
}
plot_thread.setRunning(true);
}
public void PlotPoints(Canvas canvas){
if(D) Log.i(TAG, "Обновляем экран");
// clear screen
canvas.drawColor(Color.rgb(255, 255, 255));
// draw grids
for(int vertical = 1; vertical<10; vertical++){
canvas.drawLine(
vertical*(width/10)+1, 1,
vertical*(width/10)+1, heigth+1,
grid_paint);
}
for(int horizontal = 1; horizontal<10; horizontal++){
canvas.drawLine(
1, horizontal*(heigth/10)+1,
width+1, horizontal*(heigth/10)+1,
grid_paint);
}
// draw center cross
canvas.drawLine(0, (heigth/2)+1, width+1, (heigth/2)+1, cross_paint);
canvas.drawLine((width/2)+1, 0, (width/2)+1, heigth+1, cross_paint);
// draw outline
canvas.drawLine(0, 0, (width+1), 0, outline_paint); // top
canvas.drawLine((width-1), 0, (width-1), (heigth+1), outline_paint); //right
canvas.drawLine(0, (heigth+1), (width+1), (heigth+1), outline_paint); // bottom
canvas.drawLine(0, 0, 0, (heigth+1), outline_paint); //left
// plot data
for(int x=0; x<(width-1); x++){
canvas.drawLine(x+1, ch1_data[x], x+2, ch1_data[x+1], ch1_color);
}
}
}Код: Выделить всё
public class MainActivity extends Activity {
private int MAX_SAMPLES = 320;
private int[] ch1_data = new int[MAX_SAMPLES];
private Handler mHandler = new Handler();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
int i;
for(i=0; i < ch1_data.length; i++) {
ch1_data[i] = 0;
}
Thread t = new Thread(new Runnable() {
public void run() {
int i;
try {
while(ThreadCalc){
TimeUnit.MILLISECONDS.sleep(1000/MAX_SAMPLES); // на экране отображаем данные, полученные за 1 сек.
for(i=0; i < ch1_data.length; i++) {
if (i == MAX_SAMPLES - 1){
ch1_data[i] = new Random().nextInt(27500) + 5; // для теста заполняем массив случайными числами
} else {
ch1_data[i] = ch1_data[i + 1];
}
}
mHandler.post(updateWaveform);
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
Runnable updateWaveform = new Runnable() {
public void run() {
if(D) Log.i(TAG, "Отправляем данные на отрисовку");
mWaveform.set_data(ch1_data); // отправляем собранные данные на отрисовку
}
};
public synchronized void onPause() {
super.onPause();
mHandler.removeCallbacks(updateWaveform);
}
}Соответственно Логи выглядят следующим образом:
Первые ~полсекунды:
Отправляем данные на отрисовку
Принимаем данные и обрабатываем
Обновляем экран
Отправляем данные на отрисовку
Принимаем данные и обрабатываем
Обновляем экран и т.д. ...
А затем:
Отправляем данные на отрисовку
Принимаем данные и обрабатываем
Отправляем данные на отрисовку
Принимаем данные и обрабатываем
Отправляем данные на отрисовку
Принимаем данные и обрабатываем ...
Я так понимаю, что SurfaceView через ~500 мсек просто перестает успевать рисовать. Помогите разобраться.