Как стать автором
Обновить
8
0
BorisPlus @BorisPlus

Пользователь

Отправить сообщение
Спасибо, хорошая статья.
Заменить «Этак кнопка...» на «Эдак кнопка...» )
И мне Ant как-то роднее. Переработал. Пригодилось. Спасибо!
Это хорошо, но что бы я не пробовал, но такие вот простые вещи не всегда работали так как надо.
Некоторые радио вещатели хитрят и пускают теги с описанием текущей песни несинхронизировано
с непосредственным звучанием. Например в плеере уже говорится, что будет звучать «вот такая вот песня»,
а на самом деле идет реклама.
Тут надо математику прикручивать, что-то типа распознавания образов и т.п. для слияния «музыкальных отрезков».
Короче, все решаемо, но только через костыли.Мигание экрана можно решить 2 способами
1)либо блокировать именно ту часть экрана, где что-то нужно нарисовать, но если области не хватит, то нарисуется обрезанный объект и если на фоне объекта было уже что-то то это что-то затрется прямоугольной областью (которую собственно мы и блокируем и в которую вписывается рисуемый новый объект). пробовал устанавливать прозрачность канвы, но не выходит пока.
2)либо воспользоваться следующим мегарешением — все минусы и особенности первого варианта просто напрочь отсутствуют, не надо ничего рассчитывать, нужно просто лишний раз производить блокировку — "холостую блокировку" канвы «lockCanvas(new Rect(0,0,0,0))+unlock», а до или после уже блокировать lockCanvas(null) и рисовать, тогда четные и нечетные рисуютя на одном экране. и тогда кстати можно что хочешь дорисовывать по требованию.

вот такой костыль, не знаю — баг это или фича SDK или эмулятора.Но костыль этот учтите. Отчитался. всем спасибо.
Так, ни у кого исключение по выходу из программы не выдает?
Итак, вот пример программы с различной логикой вариантов рисования на экране. Смотрите комментарии и меняйте значение mySurfaceView.JUST_CHANGE_DEFAULT_DRAWING_LOGIC_VARIANT
В комментариях отписал, что и как вызывается и что мне не очень нравится в том или ином варианте.
MainActivity
package com.example.surfaceviewexample;

import android.os.Bundle;
import android.app.Activity;
import android.graphics.Canvas;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.widget.Toast;

public class MainActivity extends Activity {

	MySurfaceView mySurfaceView;
	BackgroundThread backgroundThread;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mySurfaceView = new MySurfaceView(this);
        setContentView(mySurfaceView); 
        
    }    

	//BackgroundThread knows about only MainActivity and call this.parent.draw
    //but MainActivity knows about MySurfaceView and delegate draw to its "draw" method 
    public void draw(int number) {
    	switch(mySurfaceView.JUST_CHANGE_DEFAULT_DRAWING_LOGIC_VARIANT){
			case(1):
			case(2):
			case(3):
			case(5):
			case(6):{
				mySurfaceView.draw(number);
				break;			
			}
			case(4):{				
				final int i = number;
				new Thread(new Runnable(){
					public void run(){
						mySurfaceView.post(new Runnable(){
							public void run(){
								mySurfaceView.draw(i);
							}
						});
					}
				}).start();			
			}
    	}	
    	
	}
    @Override
    protected void onStart() {

      	super.onStart();
        backgroundThread = new BackgroundThread(this);
        backgroundThread.start();
    }
    @Override
    protected void onStop() {
      	super.onStop();
      	if(backgroundThread!=null){
      		backgroundThread.stop();
      		backgroundThread = null;
      	}
    	
    }
    @Override
    protected void onDestroy() {
    	super.onDestroy();  	
  		if(backgroundThread!=null){
  			backgroundThread.destroy();
  			backgroundThread = null;
  		}      
    }
}

BackgroundThread
package com.example.surfaceviewexample;

public class BackgroundThread extends Thread {
	//It knows about only MainActivity and call this.parent.draw
	MainActivity parent;
	int index = 1;
	public BackgroundThread(MainActivity parent) {
		this.parent = parent;
 	}

	public void run() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}		
		while (true) {
			this.parent.draw(index++);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

MySurfaceView
package com.example.surfaceviewexample;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
	DrawingThread drawingThread;
	ArrayList<Integer> stack = new ArrayList<Integer>();
	public int JUST_CHANGE_DEFAULT_DRAWING_LOGIC_VARIANT = 6;///1,2,3,4,5,6
	//1 - start drawingThread.draw - drawingThread is only one - not work - canvas blinks
	//1 - запуск в лоб drawingThread.draw - drawingThread один - экран мерцает четный/нечетный
	//2 - start drawingThread.draw in new Thread - it may be very difficult for comprehension - drawingThread is only one - not work - canvas blinks
	//2 - запуск в новой нити исполнения drawingThread.draw - это сложно для понимания, но кто-то так просто посоветовал попробовать - drawingThread один - экран мерцает четный/нечетный
	//3 - create every time new DrawingThread and start him  - drawingThread not declared and there are many DrawingThread objects - not work - canvas blinks
	//3 - каждый раз создается и стартуется новый DrawingThread - drawingThread вообще не объявляется - экран мерцает четный/нечетный
	//4 - using existing method "post" of SurfaceView of Runnable interface, see MySurfaceView.draw case 4 - экран мерцает четный/нечетный
	//4 - используется существующий метод "post" суперкласса SurfaceView, см. MySurfaceView.draw вариант 4 - экран мерцает четный/нечетный
	//5 - work well - there is one DrawingThread object and it have to store stack of all drawing Objects - I dont't like existing stack and idling process, not call on demand
	//5 - работает по интерфейсу пользователя как надо - и drawingThread только один, и есть стек отображаемых объектов - Мне не нравится, что для того чтоб дорисовать объект, нужно хранить и перерисовывать весь стек, есть холостой ход фонового потока рисования, а хочется отрисовку объекта по требованию
	//6 - work well - but there are more DrawingThread objects and it have to store stack of all drawing Objects - I dont't like existing stack. There is call on demand, although some people say that it is no good use multithread access to UI.
	//6 - работает по интерфейсу пользователякак надо - каждый раз создается и стартуется новый DrawingThread, и есть стек всех отображаемых объектов - Мне не нравится, что для того чтоб дорисовать объект, нужно хранить и перерисовывать весь стек. Но реализована отрисовка по требованию, хотя многие разработчики предостеригают от создания множества нитей, используемых для рисования на одной канве.
	//7 шутки ради
	public MySurfaceView(Context context){
		super(context);
		getHolder().addCallback(this);		
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {		
	}


	//BackgroundThread knows about only MainActivity and call this.parent.draw
    //but MainActivity knows about MySurfaceView and delegate draw to its "draw" method
    //but MySurfaceView knows how to draw object well, but delegates draw to "DrawingThread.draw" method
	public void draw(int index){
		switch(this.JUST_CHANGE_DEFAULT_DRAWING_LOGIC_VARIANT){
			case(1):
			case(4):{
				drawingThread.draw(index);
				break;			
			}
			case(2):{
				final int i = index;
				new Thread(new Runnable(){
					public void run(){
						drawingThread.draw(i);
					}
				}).start();
				break;			
			}
			case(3):{
				(new DrawingThread(getHolder(),this,index)).start();
				break;			
			}			
			case(5):{
				stack.add(index);
				break;			
			}			
			case(6):{
				stack.add(index);
				(new DrawingThread(getHolder(),this)).start();
				break;			
			}
		}			
	}
	public void draw(Canvas canvas, int number){
		//super.onDraw(canvas);
		switch(this.JUST_CHANGE_DEFAULT_DRAWING_LOGIC_VARIANT){
			case(1):
			case(2):
			case(3):
			case(4):{
				Paint p = new Paint();
				p.setTextSize(canvas.getHeight()/50);
				p.setColor(Color.RED);
				canvas.drawText(""+number, p.getTextSize(), p.getTextSize()*(number), p);
				break;			
			}
			case(5):
			case(6):{	
				//in case 5 variable "number" is not using - this is stack 
				Paint p = new Paint();
				p.setTextSize(canvas.getHeight()/50);
				p.setColor(Color.RED);
				for(Integer int_item : stack){
					canvas.drawText(""+int_item, p.getTextSize(), p.getTextSize()*(int_item), p);
				}
				break;
			}
		}
	}
	
	public void surfaceCreated(SurfaceHolder holder) {
		switch(this.JUST_CHANGE_DEFAULT_DRAWING_LOGIC_VARIANT){
			case(1):
			case(2):
			case(4):
			case(5):{
				drawingThread = new DrawingThread(getHolder(),this);
				drawingThread.start();
				break;			
			}
			case(3):
			case(6):{
				//Nothing else matter
				break;
			}
		}
	}

	public void surfaceDestroyed(SurfaceHolder holder) {		
		switch(this.JUST_CHANGE_DEFAULT_DRAWING_LOGIC_VARIANT){
			case(1):
			case(2):
			case(4):
			case(5):{
				drawingThread.destroy();
				break;			
			}
			case(3):
			case(6):{
				//Nothing else matter
				break;
			}
		}		
	}
}

DrawingThread
package com.example.surfaceviewexample;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;

public class DrawingThread extends Thread {
	SurfaceHolder surfaceHolder;
	MySurfaceView mySurfaceView;
	int number = 0;
	public DrawingThread(SurfaceHolder surfaceHolder,MySurfaceView mySurfaceView){
		super();
		this.surfaceHolder = surfaceHolder;
		this.mySurfaceView = mySurfaceView;
	}
	public DrawingThread(SurfaceHolder surfaceHolder,MySurfaceView mySurfaceView,int number){
		super();
		this.surfaceHolder = surfaceHolder;
		this.mySurfaceView = mySurfaceView;
		this.number = number;
	}
	//BackgroundThread knows about only MainActivity and call this.parent.draw
    //but MainActivity knows about MySurfaceView and delegate draw to its "draw" method
    //but MySurfaceView knows how to draw object well, but delegates draw to "DrawingThread.draw" method
    //DrawingThread dose not know how to draw object well, it blocks canvas and call necessary MySurfaceView.draw(Canvas canvas, int number)
	public void draw(int number){
		
		this.number = number;
		this.draw();
	}
	protected void draw(){
		Canvas canvas = this.surfaceHolder.lockCanvas();
		try{
			synchronized (surfaceHolder) {
				//in case 5 or 6 variable "this.number" is not using - this is stack 
				mySurfaceView.draw(canvas, this.number);
			}									
		}
		finally{			
			if(canvas!=null){
				surfaceHolder.unlockCanvasAndPost(canvas);
			}			
		}
	}
	public void run(){
		switch(mySurfaceView.JUST_CHANGE_DEFAULT_DRAWING_LOGIC_VARIANT){
			case(1):
			case(2):{
				while(true){}	
			}
			case(3):{
				this.draw();
				break;
			}
			case(4):{
				//Nothing else matter
				break;
			}
			case(5):{
				//Nothing else matter
				while(true){this.draw();}	
			}
			case(6):{
				//Nothing else matter
				this.draw();	
				break;
			}
		}			
	}

}


Если кто-то все же будет разгребать и у него не пойдет, пишите в личку, скину исходник архивом.
«поток просто крутится и вызывает методы update и render из SurfaceView»
да, именно так сейчас и сделано в одном из вариантов, так как именно SurfaceView должен знать как «правильно» рисовать, а вот когда ему рисовать, это уже определяет этот фоновый поток рисования.

Задача была какая — Нужно чтоб на канве оставалось все ранее нарисованное, а при новом вызове просто дорисовывалось поверх. при этом, во всех моих уже «рабочих» вариантах тестовой программы (которые не меорцают) приходится
1) перерисовывать весь канвас. то есть хранить все ранее нарисованные элементы в стеке объектов и при перерисовывании формы их всех последовательно и рисовать.
2) поток рисования работает в пустую — «маслает» себе и «маслает» бесконечно, я вот не пойму не уже ли никак нельзя асинхронно вызвать какой-то метод рисования на канве, то есть не просто поток висит и рисует что-то в соответствии с изменившимся стеком объектов, а вызывать по-требованию. сейчас я просто по требованию вызываю новый поток, который и перерисовывает канву в соответствии с хранящимся стеком объектов и завершается по окончании перерисовывания.

наверно так и надо подходить к решению такой задачи. вариант задачи (у меня она в этой части похожая, только я по меню не счелкаю, за меня вызывает отрисовку фоновый поток)
выбрал в меню «нарисовать квадрат» — объект добавился в стрек и вызвался поток перерисовки канвы в соответствии со всем стеком
выбрал «треугольник красного цвета» — объект добавился в стрек и вызвался поток перерисовки канвы в соответствии со всем стеком

а вот смежная задача — если я хочу чтобы несколько потоков рисовали на одной канве одновременно кривые линии, как будто это два человека рисуют мелом — красным и синим например. мне что — стек всех точек хранить и перерисовывать? ужос :) Да, использование Path для отрисовки «кривой» по точкам подходит, но опять же прийдется хранить стек точек. Эту задачу я приводил лишь как пример смежной с моей задачи. А если параллельно рисоваться должны несколько линий независимо (несколькими фоновыми потоками), то это нужно уже отслеживать массив стеков точек этих кривых. Но все равно это очень как-то неправильно. Ведь для того чтоб просто дорисовать очередную точку из фонового процесса без торможения интерфейса — нужно хранить весь стек и его перерисовывать.

Сейчас pvshnik мне предложил, наверно, единственно верное решение от холостой работы фонового потока рисования — использование Android Message System в фоновом потоке. Попробую внедрить его.

Но вот сама задача фонового «дорисовывания» на канве объекта, вынуждающая хранить стек всех нарисованных ранее объектов, как-то у меня не решается без мерцания экрана. При чем при обычном подходе к этой задаче, как в вышеописанном примере, мерцание делится на четное и нечетное, при нечетной блокировке рисуются все объекты нечетного вызова, при четной — только четного вызова. А вот так чтоб рисовались все и «четные» и «нечетные» на одном экране — не выходит, выходит только если хранить их стек и перерисовывать все каждый раз заново.

Пример программы с различной логикой вариантов рисования на экране скину позже (фоновый поток есть/нет, стек есть/нет, фоновый поток один/каждый раз новый). Логика механизма рисования определяться будет значением конфигурационной переменной.
Короче, все переделал в соответствии с постом и выявил такой баг. Если перерисовывается весь экран, то есть если происходит в потоке вызов onDraw(locked_canvas), то все хорошо, а если дорисовывать на канве еще что-то, используя locked_canvas.draw(...), то экран мерцает.

зачем оно тогда все это нужно, если можно аналогично перерисовывать все, используя invalidate() и обычный View?! Поговаривают, это происходит на версии Андройда ниже 2.2.
Так, что-то я не могу никак привести мысли в порядок.
п.1) Есть у меня класс-модель
п.2) Есть у меня класс-представление, которое знает как «рисовать» класс-модель
п.3) Есть фоновый поток, который, обрабатывая данные «из вне», передает в представление итоговый объект класса-модели и вызывает у представления invalidate().

Чтобы переработать исходное приложение в соответствии с указанной статьей:

а) теперь DrawThread должен знать как «рисовать» класс-модель, а не класс-представление. Меня как-то это напрягает. Ведь если DrawThread действительно знает как «рисовать» класс-модель, то зачем нужен SurfaceView?
б) теперь нужно из фонового потока п.3 вызывать DrawThread c переданным в него объектом класса-модели, чтоб тот его и нарисовал.

Я правильно все понимаю? Это даст прироста производительности действительно?

Интересно. Хотя и забавно вышло. Не успел ознакомиться с В пень free-lance.ru! и Free-lance.ru сошёл с ума, как вижу эту статью.
Ну а теперь, чтоб было все просто красиво, как с подбором длинны иглы в опыте Бюффона, чтоб получить точное зачение Пи за одно-два бросания. Распознаем ноту Ля большой октавы (110 Гц). О-па! Чётко.
Попробовал распознать ноту Ми (82.406 Гц). Получилось.


clear all% Очистка памяти
[Signal,hc,bits] = wavread('E2.wav');%Файл с длинным звучанием ноты

%% Параметры
Tm=0.5;% Длина сигнала (с)
Fd=hc;% Частота дискретизации (Гц), у меня была 22050 из wav характеритстика
FftL=Fd*2;% Количество линий Фурье спектра
Epsilon=50;% Окрестность максимальной частоты для наглядного графика n.3
Signal = transpose(Signal(1:(Fd*Tm)));% все же берем отрезок сигнала

%% Спектральное представление сигнала
FftS=abs(fft(Signal,FftL));% Амплитуды преобразования Фурье сигнала
FftS=2*FftS./FftL;% Нормировка спектра по амплитуде
FftS(1)=FftS(1)/2;% Нормировка постоянной составляющей в спектре

F=0:Fd/FftL:Fd/2-1/FftL;% Массив частот вычисляемого спектра Фурье
[C,i] = max(FftS);%Максимум и его аргумент вмассиве частот спектра

%% Построение графиков
figure( 'NumberTitle','off',...
        'Name','BorisPlus: распознование ноты (Ми большой октавы/E2) из файла')

subplot(3,1,1);% Выбор области окна для построения
plot(Signal);% Построение сигнала
title('Сигнал');% Подпись графика
xlabel('Время(с)');% Подпись оси х графика
ylabel('Ампл.');% Подпись оси у графика

subplot(3,1,2);% Выбор области окна для построения
plot(F,FftS(1:length(F)));% Построение спектра Фурье сигнала
title('Спектр сигнала');% Подпись графика
xlabel('Частота(Гц)');% Подпись оси х графика
ylabel('Ампл.');% Подпись оси у графика

subplot(3,1,3);% Выбор области окна для построения
plot(   F(max(1,i-Epsilon):min(length(F),i+Epsilon)),...
        FftS(max(1,i-Epsilon):min(length(F),i+Epsilon)),'-r',...
        F(i),FftS(i),'ko');% Посмотрим наглянее у максимума
title('Спектр сигнала в окрестности максимума');
xlabel('Частота(Гц)');% Подпись оси х графика
ylabel('Ампл.');% Подпись оси у графика
text(F(i)+1,FftS(i),[num2str(F(i)) ' ' 'Гц']);% Подпись точки максимума

Есть мысль развить сие. Спасибо за толчок.
Круто. Молодчина.
Странно, но и у меня всплыла именно эта фраза в памяти… не ясно почему за цитату из романа «Лабиринт отражений» ( и др.) Лукьяненко товарищу redlaber'у поставили минусы. Там тоже были костюмы с датчиками в разных местах (во всех «разных»), использовались для «погружения» в виртуальный игровой мир. Не для рекламы опишу подробнее: там был так называемый Дайвер, кто мог погружаться и находится в такой реальности неограниченно долго, пока не припрет, так сказать. Этим и зарабатывал. Но и у него иногда подвисали интерфейсы, и чтобы выйти, он говорил «Глубина, глубина, я не твой». Там и вирусы, там и программеры, там и геймеры. Все в костюмчиках. И чем эта цитата хуже картинок выше. Не знаю.
Нет-нет, вышло замечательно. Пишите, доступно для восприятия, даже если это и отклоняется от общей линии темы.
Вот лично мне кажется, что если бы шла речь о проведенном научном исследовании Apple, результатом которого стало что-то типа — «углы терминальных устройств пользователей в целях повышения удобства использования и иных прагматичных целях (протирание карманов брюк пользователей острыми углами, большая скалываемость углов, приводящая с вероятностью в 0,99 к последующей поломке устройства в целом...) должны иметь округлую форму с радиусом кривизны, рассчитываемым по формуле...», то тут еще как-то можно, по-моему, говорить, что за это можно придумать мзду, и то, только в том случае, если эти устройства попадут под данную «формулу», хотя наука в чистом виде не приемлет такого рода поборов… Но вот просто так — за скругленность, клик по экрану, фишки с мультитачем и т.п. как-то печально это.
И к какому развитию технологий могут привести такого рода патенты. Как что-то развивать? Какими темпами это будет происходить? Так что нужно это дело обсуждать, мусолить, если кому-то и поднадоела эта шумиха, перелистни страницу со статьей и просто не читай. А обсуждать нужно непременно.
1

Информация

В рейтинге
Не участвует
Откуда
Россия
Зарегистрирован
Активность