问题
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
回答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.
回答2:
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);
}
}
}
}
来源:https://stackoverflow.com/questions/11366537/android-live-wallpaper-doesnt-show