1

i have just started learning live wallpapers and i made this little thing.

the thing is my app compiles with out any problems.

as i open it in the phone it shows the wallpaper in the preview but when i click "set as wallpaper" it somehow crashes, and returns the front screen, and my wallpaper turns black, but it doesn't run it.

my guess is the problem is some where along the onDestory() ..

public class Strips extends WallpaperService {

private StripsEngine engine;

@Override
public void onCreate() {
    super.onCreate();
    engine = new StripsEngine();
    engine.resume();

}

@Override
public void onDestroy() {
    super.onDestroy();
    engine.pause();
}

@Override
public Engine onCreateEngine() {

    return engine;
}

class StripsEngine extends Engine implements Runnable {
    private Thread t = null;
    private SurfaceHolder holder;
    private boolean clearToRun = false;
    private Paint paint = new Paint();
    private Paint paint2 = new Paint();
    private int frame;
    private float endX,endY;
    private int height, width;
    private Canvas c;


    StripsEngine() {
        holder = getSurfaceHolder();
        paint.setColor(Color.WHITE);
        paint.setStrokeWidth(30);
        paint.setAntiAlias(true);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStyle(Paint.Style.STROKE);
        paint2 = paint;
        paint2.setColor(Color.BLACK);
        paint2.setStrokeWidth(40);
        frame = 0;
    }

    void drawStrips() {

    }

    public void run() {
        // TODO Auto-generated method stub
        while (clearToRun) {
            if (!holder.getSurface().isValid()) {
                continue;
            }
            height = 800;
            width = 480; 

            endX = (frame) % (width + 10);
            endY = (frame / 3) % (height + 10);

            if (endX == 0)
                paint.setARGB(255,(int)(Math.random()*255), (int)(Math.random()*255),(int)(Math.random()*255));
            if (endY ==0)
                paint.setARGB(255,(int)(Math.random()*255), (int)(Math.random()*255),(int)(Math.random()*255));


            c = holder.lockCanvas();
            c.drawLine(endX-30, endY-10, endX , endY,paint);
            c.drawLine(endX-30, endY-10, endX , endY,paint);
            holder.unlockCanvasAndPost(c);
            frame = frame +2;
            }
    }
    public void pause() {
        clearToRun = false;
        while (true) {
            try {
                t.join();
            }
            catch (InterruptedException e) {
                e.printStackTrace();    
            }
            break;
        }
        t = null;
    }

    public void resume() {
        clearToRun = true;
        t = new Thread(this);

        t.start();
    }
}

}

07-06 17:14:43.869: E/Surface(478): error dequeuing a buffer (Unknown error: -19) 07-06 17:14:43.869: E/Surface(478): dequeueBuffer failed (No such device) 07-06 17:14:43.869: E/BaseSurfaceHolder(478): Exception locking surface 07-06 17:14:43.869: E/BaseSurfaceHolder(478): java.lang.IllegalArgumentException 07-06 17:14:43.869: E/BaseSurfaceHolder(478): at android.view.Surface.lockCanvasNative(Native Method) 07-06 17:14:43.869: E/BaseSurfaceHolder(478): at android.view.Surface.lockCanvas(Surface.java:288) 07-06 17:14:43.869: E/BaseSurfaceHolder(478): at com.android.internal.view.BaseSurfaceHolder.internalLockCanvas(BaseSurfaceHolder.java:132) 07-06 17:14:43.869: E/BaseSurfaceHolder(478): at com.android.internal.view.BaseSurfaceHolder.lockCanvas(BaseSurfaceHolder.java:112) 07-06 17:14:43.869: E/BaseSurfaceHolder(478): at com.mendel.strips.Strips$StripsEngine.run(Strips.java:81) 07-06 17:14:43.869: E/BaseSurfaceHolder(478): at java.lang.Thread.run(Thread.java:1096) 07-06 17:14:43.972: W/dalvikvm(478): threadid=15: thread exiting with uncaught exception (group=0x4001b188) 07-06 17:14:43.979: E/AndroidRuntime(478): Uncaught handler: thread Thread-8 exiting due to uncaught exception 07-06 17:14:43.990: E/AndroidRuntime(478): java.lang.NullPointerException 07-06 17:14:43.990: E/AndroidRuntime(478): at com.mendel.strips.Strips$StripsEngine.run(Strips.java:82) 07-06 17:14:43.990: E/AndroidRuntime(478): at java.lang.Thread.run(Thread.java:1096) 07-06 17:14:43.999: I/dalvikvm(478): threadid=7: reacting to signal 3 07-06 17:14:43.999: E/dalvikvm(478): Unable to open stack trace file '/data/anr/traces.txt': Permission denied

Daniel Mendel
  • 506
  • 5
  • 17

2 Answers2

1

It's probably because the canvas you are requesting with holder.lockCanvas() is not available yet, so it's null, and you get a NullPointerException.

See the documentation of lockCanvas()

The returned Canvas can be used to draw into the surface's bitmap. A null is returned if the surface has not been created or otherwise can not be edited. You will usually need to implement Callback.surfaceCreated to find out when the Surface is available for use.

Update:

According to the doc of isValid(), which you are calling before - Does this object hold a valid surface? Returns true if it holds a physical surface, so lockCanvas() will succeed. Otherwise returns false.

The canvas should not be null at that point. But I found this, seems to be a bug of Android:

http://code.google.com/p/android/issues/detail?id=19245

So you probably have to try out the Callback.surfaceCreated approach, or, if nothing else works, try a timeout like the poster (who deleted the post), suggested, but that's really something you should avoid because it's unreliable and messy.

User
  • 31,811
  • 40
  • 131
  • 232
  • i don't get it, where should i implement that? at the run method i do check if the surface is valid before trying to lock the canvas, just after the while i have an if holder.getSurface().isValid() – Daniel Mendel Jul 06 '12 at 17:42
  • You are correct, the documentation from isValid() says `Does this object hold a valid surface? Returns true if it holds a physical surface, so lockCanvas() will succeed. Otherwise returns false. ` So it should succeed, according to that. Have you tried to debug the code, I'm just guessing the line number because your file is not complete, so I can't know if it's the line accessing the canvas... maybe is a few lines before or later – User Jul 06 '12 at 18:00
  • this is all of my java file, i don't hide anything else, but the thing is that the app shows the preview fine only when i click set wallpaper or back, which it needs to call the on destory method than it crashes – Daniel Mendel Jul 06 '12 at 18:02
  • The file also contains package and import lines and spaces between them... Just look at line 82, there the object is null. If it's the canvas, we have to investigate why it's null after isValid() returned true. – User Jul 06 '12 at 18:11
0

I got the answer!

i have looked through the cube live wallpaper sample and copied the structure, here is the code:

public class Strips extends WallpaperService {

private final Handler mHandler = new Handler();   
@Override
public void onCreate() {
    super.onCreate();

}

@Override
public void onDestroy() {
    super.onDestroy();
}

@Override
public Engine onCreateEngine() {

    return new StripsEngine();
}

class StripsEngine extends Engine   {
    private Thread t = null;
;
    private boolean clearToRun = false;
    private Paint paint = new Paint();
    private Paint paint2 = new Paint();
    private int frame;
    private float endX,endY;
    private int height, width;
    private Canvas c;

    private final Runnable mDrawStrip = new Runnable() {
        public void run() {
            drawFrame();
        }
    };


    StripsEngine() {
        paint.setColor(Color.WHITE);
        paint.setStrokeWidth(30);
        paint.setAntiAlias(true);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStyle(Paint.Style.STROKE);
        paint2 = paint;
        paint2.setColor(Color.BLACK);
        paint2.setStrokeWidth(40);
        frame = 0;
    }

     @Override
        public void onDestroy() {
            super.onDestroy();
            mHandler.removeCallbacks(mDrawStrip);
        }

     @Override
        public void onSurfaceCreated(SurfaceHolder holder) {
            super.onSurfaceCreated(holder);
        }

     @Override
        public void onSurfaceDestroyed(SurfaceHolder holder) {
            super.onSurfaceDestroyed(holder);
            clearToRun = false;
            mHandler.removeCallbacks(mDrawStrip);
        }


     @Override
        public void onVisibilityChanged(boolean visible) {
            clearToRun = visible;
            if (visible) {
                drawFrame();
            } else {
                mHandler.removeCallbacks(mDrawStrip);
            }
        }


    public void drawFrame() {
        // TODO Auto-generated method stub
     final SurfaceHolder holder = getSurfaceHolder();
       Canvas c = null;
       try {
           c = holder.lockCanvas();
           if (c != null) {
               // draw something
            height = 800;
            width = 480; 

            endX = (frame) % (width + 10);
            endY = (frame / 3) % (height + 10);


            if (endX == 0)
                paint.setARGB(255,(int)(Math.random()*255), (int)(Math.random()*255),(int)(Math.random()*255));
            if (endY ==0)
                paint.setARGB(255,(int)(Math.random()*255), (int)(Math.random()*255),(int)(Math.random()*255));

            c.drawLine(endX-30, endY-10, endX , endY,paint);
            frame = frame +2;
           }
       } finally {
           if (c != null) holder.unlockCanvasAndPost(c);
       }
         mHandler.removeCallbacks(mDrawStrip);
            if (clearToRun) {
                mHandler.postDelayed(mDrawStrip, 1000 / 25);
            }
    }

}

}
Daniel Mendel
  • 506
  • 5
  • 17