public class SnowflakeWallpaper extends WallpaperService {
// Limit of snowflakes per snowflake type; 4 types * 4 snowflake = 16 total
// Should keep memory usage at a minimal
static int SNOWFLAKE_AMOUNT = 4;
Drawable drawWall;
Rect wallBounds;
// Draw all snowflakes off screen due to not knowing size of canvas at creation
static int SNOW_START = -90;
ArrayList<Snowflakes> snow = new ArrayList<Snowflakes>();
private final Handler mHandler = new Handler();
@Override
public void onCreate() {
super.onCreate();
//WallpaperManager to pull current wallpaper
WallpaperManager wManager = WallpaperManager.getInstance(this);
drawWall = wManager.getFastDrawable();
wallBounds = drawWall.copyBounds();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public Engine onCreateEngine() {
return new SnowEngine();
}
class SnowEngine extends Engine {
private final Runnable mDrawSnow = new Runnable() {
public void run() {
drawFrame();
}
};
private boolean mVisible;
SnowEngine() {
if(snow.size() < 16){
//Back snowflakes
for(int i = 0; i < SNOWFLAKE_AMOUNT; i++){
snow.add(new Snowflakes(
BitmapFactory.decodeResource(getResources(),
R.drawable.snowflakeback),
SNOW_START,
SNOW_START,
((float)(Math.random() * 2) + 1)) // Fall speed initial setup, back slowest to front fastest potentially
);
}
//MidBack snowflakes
for(int i = 0; i < SNOWFLAKE_AMOUNT; i++){
snow.add(new Snowflakes(
BitmapFactory.decodeResource(getResources(),
R.drawable.snowflakemid),
SNOW_START,
SNOW_START,
((float)(Math.random() * 4) + 1)
));
}
// Mid snowflakes
for(int i = 0; i < SNOWFLAKE_AMOUNT; i++){
snow.add(new Snowflakes(
BitmapFactory.decodeResource(getResources(),
R.drawable.snowflakemidfront),
SNOW_START,
SNOW_START,
((float)(Math.random() * 8) + 1))
);
}
// Front snowflakes
for(int i = 0; i < SNOWFLAKE_AMOUNT; i++){
snow.add(new Snowflakes(
BitmapFactory.decodeResource(getResources(),
R.drawable.snowflake),
SNOW_START,
SNOW_START,
((float)(Math.random() * 16) + 1))
);
}
}
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
}
@Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mDrawSnow);
}
@Override
public void onVisibilityChanged(boolean visible) {
mVisible = visible;
if (visible) {
drawFrame();
} else {
mHandler.removeCallbacks(mDrawSnow);
}
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
drawFrame();
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
mVisible = false;
mHandler.removeCallbacks(mDrawSnow);
}
/*
* Update the screen with a new frame
*/
void drawFrame() {
final SurfaceHolder holder = getSurfaceHolder();
/*
* if the snow goes too low or too right, reset;
*/
for(int i = 0; i < snow.size(); i++){
if(snow.get(i).getX() > holder.getSurfaceFrame().width()){
snow.get(i).setX(-65);
}
if(snow.get(i).getY() > holder.getSurfaceFrame().height()){
snow.get(i).setY(-69);
}
}
// Test if the array was just create; true - randomly populate snowflakes on screen
if(snow.get(1).getX() < -70){
for(int i = 0; i < snow.size(); i++){
snow.get(i).setX((int)(Math.random() * getSurfaceHolder().getSurfaceFrame().width() +1));
snow.get(i).setY((int)(Math.random() * getSurfaceHolder().getSurfaceFrame().height() + 1));
}
}
// Change snowflake x & y
for(int i = 0; i < snow.size(); i++){
snow.get(i).delta();
}
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
// call to draw new snow position
drawSnow(c);
}
} finally {
if (c != null) holder.unlockCanvasAndPost(c);
}
// Reschedule the next redraw
mHandler.removeCallbacks(mDrawSnow);
if (mVisible) {
mHandler.postDelayed(mDrawSnow, 1000 / 100);
}
}
/*
* Draw the snowflakes
*/
void drawSnow(Canvas c) {
c.save();
// Draw bg
//********** add code to pull current bg and draw that instead of black. Maybe set this in config?
if(drawWall == null){
c.drawColor(Color.BLACK);
}else{
drawWall.copyBounds(wallBounds);
drawWall.draw(c);
}
/*
* draw up the snow
*/
for(int i = 0; i < snow.size(); i++){
c.drawBitmap(snow.get(i).getImage(), snow.get(i).getX(), snow.get(i).getY(), null);
}
c.restore();
}
}
}
答案 0 :(得分:1)
与Gabe一样的问题 - 问题是什么?
一些一般性的想法: *你应该避免在构造函数中做很多工作。你的构造函数做了很多工作,应该(imho)在一些init / setup方法中。更容易在实例中创建基准/配置文件。
你在许多地方使用Math.random - 我假设你是单线程的,但是Math.random是同步的。根据javadocs:“如果许多线程需要以很高的速率生成伪随机数,它可能会减少每个线程争用自己的伪随机数生成器”
您正在使用Math.random,它会让您获得双倍,然后相乘,然后添加,然后再投射。这看起来很浪费。什么方法可以减少操作次数?
你似乎有一些分裂 - 见“mHandler.postDelayed(mDrawSnow,1000/100);”。当然,这可能是编译或JIT消失,但你应该避免在性能关键代码中划分(它比乘法慢得多)。因此,任何乘以常数的div都可以用1 / C乘以静态来代替。
您有许多重复访问方法调用(在某些情况下几乎所有重复访问)。见snippit:
for(int i = 0; i < snow.size(); i++){ if(snow.get(i).getX() > holder.getSurfaceFrame().width()){ snow.get(i).setX(-65); } if(snow.get(i).getY() > holder.getSurfaceFrame().height()){ snow.get(i).setY(-69); } }
你应该将“holder.getSurfaceFrame()。width()存储在临时/局部var中(假设你的表面可以由用户调整,每个绘制循环可能一次)。你也可以将snow.get(i)存储在一个local var。更好(样式)你可以使用增强的for循环,因为snow是一个ArrayList。所以使用
for (Snow mySnow : snow) {
// Do something with mySnow
}
希望这会有所帮助。祝你好运!