public class CannonView extends SurfaceView implements SurfaceHolder.Callback {
CannonThread cannonThread;
private Paint blockerPaint;
public CannonView(Context context, AttributeSet attrs) {
super(context, attrs);
blockerPaint = new Paint();
blockerPaint.setStrokeWidth(10.0f);
getHolder().addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
cannonThread = new CannonThread(holder);
cannonThread.running(true);
cannonThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
cannonThread.running(false);
while (retry) {
try {
cannonThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
private class CannonThread extends Thread {
boolean setRunning;
SurfaceHolder surfaceHolder;
public CannonThread(SurfaceHolder holder) {
setRunning = true;
surfaceHolder = holder;
}
public void running(boolean isRunning) {
setRunning = isRunning;
}
#Override
public void run() {
Canvas canvas = null;
while (setRunning) {
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
canvas.drawLine(0, 0, 100, 100, blockerPaint);
}
} finally {
if (canvas != null)
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
Although above code is very simple
but it is not drawing anything on my activity ..
Logcat says i am doing too much work on main thread ..62 frame skipped ..
Please help
Well this isn't my style of coding, so I decided that you need to simplify things a bit. You used the android api guides but they suck.
Watch the following videos and you should be fine.
http://www.youtube.com/watch?v=wUmId0rwsBQ&list=SP2F07DBCDCC01493A&index=67
http://www.youtube.com/watch?v=0wy907WZFiA&list=SP2F07DBCDCC01493A
http://www.youtube.com/watch?v=ZMcYbf9Hhe4&list=SP2F07DBCDCC01493A
http://www.youtube.com/watch?v=yowNavIDzzE&list=SP2F07DBCDCC01493A
Related
I'm working on a video into a SurfaceView.
My goal is to get recurrent bitmaps of the running video.
Here is my Custom implementation:
private static final String TAG = "XXX";
private Activity activity;
private SurfaceHolder mSurface;
private MediaPlayer mMediaPlayer;
private SurfaceHolder mActiveSurface;
public ImageView imageView;
boolean locked, locked1;
private boolean isCreated;
public AlphaSurfaceView(Context context,Activity activity) {
super(context);
getHolder().addCallback(this);
setWillNotDraw(false);
this.activity = activity;
}
public AlphaSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AlphaSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
}
#Override
public void onDraw(Canvas canvas) {
//super.onDraw(canvas);
if(isCreated){
if(getHolder() != null && getHolder().getSurface().isValid()){
Canvas c = null;
try {
if(!locked){
try {
c = getHolder().lockCanvas();
locked = true;
}catch (IllegalArgumentException e){
e.printStackTrace();
locked = false;
}
BitmapDrawable bdrawable = new BitmapDrawable();
bdrawable.draw(c);
}
}catch (Exception e){
e.printStackTrace();
locked = false;
}finally {
if(c != null && locked){
getHolder().unlockCanvasAndPost(c);
locked = false;
}
}
}
}else{
super.onDraw(canvas);
}
invalidate();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mSurface = holder;
mMediaPlayer = MediaPlayer.create(getContext(), Uri.parse("XX"), mSurface);
mActiveSurface = mSurface;
try {
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mMediaPlayer.start();
mMediaPlayer.setLooping(true);
}
});
} catch (Exception e) {
e.printStackTrace();
}
this.isCreated = true;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d(TAG, "surfacechanged");
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mMediaPlayer.stop();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mMediaPlayer.stop();
}
The problem is an IllegalArgumentException occured by the lockCanvas() method.
I tried many possibilities as:
Adding some boolean (locked & creation of surfaceview)
Test if surface is valid
even add exported="true" in targeted activity in Manifest's xml
By the way the first idea was to use getDrawingCache() but even i added setCacheEnabled(true), the return was null.
So how to resolve this Exception or using another way to get each frame?
Thanks!
You can't draw on a Surface and send a video to it. A Surface is the producer end of a producer-consumer pair, and you can only have one producer at a time.
The easiest way to have a Canvas overlap a SurfaceView Surface is to draw on the View part of the SurfaceView. Send the video to the Surface, and use onDraw() (like a custom view) to draw on the View.
Bear in mind that the Surface is a separate layer that sits behind the View UI layer, so you will need to draw on the View with transparency to see the Surface contents.
Another approach is to use multiple overlapping SurfaceViews, but this is less efficient and more limited. An example with three overlapping Surfaces can be found in Grafika's multi-surface test Activity.
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
Log.e("video","surfaceChanged");
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
Log.e("video","surfaceCreated");
mediaPlayer.setDisplay(surfaceHolder);
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
Log.e("video","surfaceDestroyed");
if (mediaPlayer != null) mediaPlayer.release();
}
});
That should help.
Let the MediaPlayer do the drawing thing.
In my android app i have activity containing a surfaceview. I want to start the surfaceview thread when the surfaceview/activity is visible to user. I have tried starting the thread in OnSurfaceCreated. That works but on some mobiles(samsung) The activity takes many seconds to become visible.The screen turns black when i resume activity. So i googled and found that when a view becomes visible onFocusChanged is called. I tried implementing OnFocusChanged in surfaceview but it is never called. below is my surfaceview class.
public class ImageSurface extends SurfaceView implements SurfaceHolder.Callback {
private DrawThread drawThread;
private SurfaceHolder sHolder;
private ImageHolder imageHolder;
Bitmap mybit;
Bitmap orgiBitmap;// ;)
int message;
Context context;
private String valMagField;
public ImageSurface(Context context, AttributeSet attrs) {
super(context, attrs);
this.context=context;
SurfaceHolder holder = getHolder();
holder.addCallback(this);
setFocusable(true);
clearFocus();
drawThread = new DrawThread(context);
}
public void setImageHolder(ImageHolder imageHolder){
this.imageHolder = imageHolder;
}
public void setBitmap(String filePath){
}
public void resume(){
drawThread.resumeThread();
}
#Override
public void onFocusChanged(boolean focus,int direction,Rect rect){
super.onFocusChanged(focus, direction, rect);
Log.d("in focus changed","onfocuschanged"+System.currentTimeMillis());
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
drawThread.setSurfaceSize(width, height);
resume();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
long startTime, stopTime;
startTime = System.currentTimeMillis();
sHolder = holder;
drawThread.setRunning(true);
if(drawThread.getState()==Thread.State.NEW){
drawThread.start();
}
if(drawThread.getState()==Thread.State.TERMINATED){
drawThread = new DrawThread(context);
drawThread.setRunning(true);
drawThread.start();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
drawThread.pauseThread();
}
class DrawThread extends Thread{
int value=0;
private Boolean drun;
int valSize =30;
Context context;
private int sHeight , sWidth;
int lastmessage;
boolean threadPaused= false;
public DrawThread(Context context){
drun = false;
this.context = context;
}
public void pauseThread(){
synchronized(this){
threadPaused = true;
this.notify();
}
}
public void resumeThread(){
synchronized(this){
threadPaused = false;
this.notify();
}
}
public void setRunning(Boolean run){
drun = run;
}
public boolean isRunning(){
return drun;
}
public void setSurfaceSize(int width , int height){
sWidth = width;
sHeight = height;
}
#Override
public void run(){
while(drun){
Canvas c = null;
//Log.d("yes","thread is running");
try{
synchronized(this){
if(threadPaused)
try {
this.wait();
} catch (InterruptedException e) {
Log.d("in wait of surface view thread","error"+e.toString());
}
}
c = sHolder.lockCanvas(null);
synchronized(sHolder){
updateCanvas(c);
}
}finally {
if(c!=null){
sHolder.unlockCanvasAndPost(c);
}
}
}
}
private void updateCanvas(Canvas canvas){
try{
if(imageHolder.dispBit!= null){
int x=(sWidth-imageHolder.dispBit.getWidth())/2,y=(sHeight-imageHolder.dispBit.getHeight())/2;
imageHolder.applyEffects();
if(canvas!=null)
canvas.drawBitmap(imageHolder.dispBit, x,y,null);
}
else if(imageHolder!=null)
imageHolder.setDisplaySize(sWidth, sHeight);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
i am using a surface view to draw interactive piechart. here is my code which will looks like all surface view examples.
class PieChart extends SurfaceView implements SurfaceHolder.Callback {
public PieChart(Context context) {
super(context);
// Log.i("PieChart", "PieChart : constructor");
getHolder().addCallback(this);
}
#Override
public void onDraw(Canvas canvas) {
if (hasData) {
resetColor();
try {
canvas.drawColor(getResources().getColor(R.color.graphbg_color));
graphDraw(canvas);
} catch (ValicException ex) {
}
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.i("PieChart", "surfaceChanged");
}
public int callCount = 0;
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
// Log.i("PieChart", "surfaceCreated");
mChartThread = new ChartThread(getHolder(), this);
mChartThread.setRunning(true);
if (!mChartThread.isAlive()) {
mChartThread.start();
}
Rect mFrame = holder.getSurfaceFrame();
mOvalF = new RectF(0, 0, mFrame.right, mFrame.right);
} catch (Exception e) {
// No error message required
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Log.i("PieChart", "surfaceDestroyed");
boolean retry = true;
callCount = 0;
mChartThread.setRunning(false);
while (retry) {
try {
mChartThread.join();
retry = false;
} catch (InterruptedException e) {
// No error message required
}
}
}
}
class ChartThread extends Thread {
private SurfaceHolder mSurfaceHolder;
private PieChart mPieChart;
private boolean mRefresh = false;
public ChartThread(SurfaceHolder surfaceHolder, PieChart pieChart) {
// Log.i("ChartThread", "ChartThread");
mSurfaceHolder = surfaceHolder;
mPieChart = pieChart;
}
public void setRunning(boolean Refresh) {
// Log.i("ChartThread", "setRunning : " + Refresh);
mRefresh = Refresh;
}
#Override
public void run() {
Canvas c;
// Log.i("ChartThread", "run : " + mRefresh);
while (mRefresh) {
c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
// c.drawColor(0xFFebf3f5);
synchronized (mSurfaceHolder) {
mPieChart.onDraw(c);
}
} catch (Exception ex) {
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
with this i am able to draw pie charts successfully. but here the issue is "before loading pie chart black rectangle is visible for a second which is surfaceview's default back ground". so I want to set background color for surface view to avoid the black rectangle.
The following is the changed code for drawing background color to surface view.
public PieChart(Context context) {
super(context);
// Log.i("PieChart", "PieChart : constructor");
getHolder().addCallback(this);
setBackgroundColor(getResources().getColor(R.color.graphbg_color));
}
#Override
public void onDraw(Canvas canvas) {
if (hasData) {
setBackgroundColor(getResources().getColor(R.color.graphbg_color));
resetColor();
try {
canvas.drawColor(getResources().getColor(R.color.graphbg_color));
graphDraw(canvas);
} catch (ValicException ex) {
}
}
}
with these changes, black rectangle issue is resolved. but piechart is not refreshing properly. can someone help me to resolve any of these two issues.
class PieChart extends SurfaceView implements SurfaceHolder.Callback {
private int backGroundColor = Color.BLACK;
public PieChart(Context context,int backGroundColor) {
super(context);
setBackGroundColor(backGroundColor);
// Log.i("PieChart", "PieChart : constructor");
getHolder().addCallback(this);
}
public void setBackGroundColor(int color){
this.backGroundColor = color;
}
#Override
public void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setStrokeWidth(3);
paint.setAntiAlias(true);
paint.setColor(backGroundColor);
canvas.drawRect(0, 0, this.getWidth(), this.getHeight(), paint);
if (hasData) {
resetColor();
try {
canvas.drawColor(getResources().getColor(R.color.graphbg_color));
graphDraw(canvas);
} catch (ValicException ex) {
}
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.i("PieChart", "surfaceChanged");
}
public int callCount = 0;
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
// Log.i("PieChart", "surfaceCreated");
mChartThread = new ChartThread(getHolder(), this);
mChartThread.setRunning(true);
if (!mChartThread.isAlive()) {
mChartThread.start();
}
Rect mFrame = holder.getSurfaceFrame();
mOvalF = new RectF(0, 0, mFrame.right, mFrame.right);
} catch (Exception e) {
// No error message required
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Log.i("PieChart", "surfaceDestroyed");
boolean retry = true;
callCount = 0;
mChartThread.setRunning(false);
while (retry) {
try {
mChartThread.join();
retry = false;
} catch (InterruptedException e) {
// No error message required
}
}
}
}
class ChartThread extends Thread {
private SurfaceHolder mSurfaceHolder;
private PieChart mPieChart;
private boolean mRefresh = false;
public ChartThread(SurfaceHolder surfaceHolder, PieChart pieChart) {
// Log.i("ChartThread", "ChartThread");
mSurfaceHolder = surfaceHolder;
mPieChart = pieChart;
}
public void setRunning(boolean Refresh) {
// Log.i("ChartThread", "setRunning : " + Refresh);
mRefresh = Refresh;
}
#Override
public void run() {
Canvas c;
// Log.i("ChartThread", "run : " + mRefresh);
while (mRefresh) {
c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
// c.drawColor(0xFFebf3f5);
synchronized (mSurfaceHolder) {
mPieChart.onDraw(c);
}
} catch (Exception ex) {
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
and in yout class client you can use the setBackGroundColor(your color) ;)
I am have some bitmaps which i want to display serially one after another but my code displays only last bitmap.Can anybody tell me why is it happening?
here is the code
class Panel extends SurfaceView implements SurfaceHolder.Callback {
private boolean _run = false;
public Panel(Context context) {
super(context);
getHolder().addCallback(this);
_run = true;
}
#Override
public void onDraw(Canvas canvas) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i("Read","surfaceChanged is called");
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i("Read","surfaceCreated is called");
while (_run ) {
display();
}
}
public void display() {
Canvas c;
c = null;
try {
c = getHolder().lockCanvas(null);
synchronized (getHolder()) {
onPreviewFrame();
invalidate();
c.drawColor(Color.BLACK);
c.drawBitmap(bmp, 10, 10, null);
//panel.surfaceDestroyed(panel.getHolder());
}
} finally {
if (c != null) {
getHolder().unlockCanvasAndPost(c);
}
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i("Read","surfaceDestroyed is called");
_run = false;
}
}
I am not sure what your requirement is but if your are trying to create a continous horizontal image scroll. Take a look at this
https://github.com/blessenm/SlideshowDemo
I'm experimenting with SurfaceView and creating simple animations with it, I don't understand why my animation (changins screen color from black to white) is working here (without using SurfaceHolder.Callback)
public class MySurface extends SurfaceView {
private boolean playing = true;
private int counter = 0;
public MySurface(Context context){
super(context);
new Anim().start();
}
private class Anim extends Thread {
#Override
public void run() {
while (playing) {
try {
sleep(1000);
draw();
counter++;
} catch (Exception e){
e.printStackTrace();
}
}
}
private void draw() {
SurfaceHolder holder = getHolder();
Canvas canvas = holder.lockCanvas();
if (canvas != null) {
if (counter % 2 == 0) {
canvas.drawColor(Color.WHITE);
} else
canvas.drawColor(Color.BLACK);
holder.unlockCanvasAndPost(canvas);
}
}
}
}
But it's not working here, what's the difference? I think it might be caused by calling .run() instead of .start()
public class MySurface extends SurfaceView implements SurfaceHolder.Callback {
Anim anim;
private boolean playing = true;
private int counter = 0;
public MySurface(Context context){
super(context);
}
// all Callbacks are overrided i didn add them to make code easier to read
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
anim = new Anim();
anim.run();
}
private class Anim extends Thread {
#Override
public void run() {
while (playing) {
try {
sleep(1000);
draw();
counter++;
} catch (Exception e){
e.printStackTrace();
}
}
}
private void draw() {
SurfaceHolder holder = getHolder();
Canvas canvas = holder.lockCanvas();
if (canvas != null) {
if (counter % 2 == 0) {
canvas.drawColor(Color.WHITE);
} else
canvas.drawColor(Color.BLACK);
holder.unlockCanvasAndPost(canvas);
}
}
}
}
EDIT: I forgot to add getHolder().addCallback(this) that caused the issue.
Could someone still point out the differnces between those two methods and tell which one is better?
EDIT2: anim.start() was also needed