我有这个:
paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
sm = new Matrix();
sm.setScale(scale, scale);
private Bitmap getImage(String n) {
File dir = context.getDir("theme", Context.MODE_PRIVATE);
File file = new File(dir, n + ".png");
if (file.exists()) {
return BitmapFactory.decodeFile(file.getAbsolutePath());
} else {
return BitmapFactory.decodeResource(getResources(), getResources().getIdentifier(n, "drawable", getPackageName()));
}
}
private Bitmap resizeImage(Bitmap b) {
return Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), sm, true);
}
public void onTouchEvent(MotionEvent event) {
#scrollable bitmaps, parallax effect
updatePosition();
}
private void draw() {
current_time = System.currentTimeMillis();
if (current_time - last_update_time >= 25) {
SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
c.drawBitmap(bitmap1, bitmap1_x, bitmap1_y, paint);
c.drawBitmap(bitmap2, bitmap2_x, bitmap2_y, paint);
...
c.drawBitmap(bitmap20, bitmap20_x, bitmap20_y, paint);
}
} finally {
if (c != null)
holder.unlockCanvasAndPost(c);
}
last_update_time = current_time;
}
}
我正在将图像调整为更大的尺寸,而不是更小。
没有调整大小,效果非常好,性能100%
bitmap1 = getImage("bitmap1");
...
bitmap20 = getImage("bitmap20");
通过调整大小,性能80%
bitmap1 = getImage("bitmap1");
...
bitmap20 = getImage("bitmap20");
called once, when screen width and height are known
bitmap1 = resizeImage(bitmap1);
...
bitmap20 = resizeImage(bitmap20);
不调整大小,画布比例,性能40%
bitmap1 = getImage("bitmap1");
...
bitmap20 = getImage("bitmap20");
set canvas.scale(scale, scale) inside draw() method
我知道有一些框架像libgdx调整图像大小而不会失去性能,但我使用的是原生画布。
问题:如何以100%的效果绘制已调整大小的图像?
更新 试图制作最小样本。
mWallpaperService.java
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.os.BatteryManager;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.service.wallpaper.WallpaperService;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.Scroller;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
public class mWallpaperService extends WallpaperService {
@Override
public Engine onCreateEngine() {
return new mEngine();
}
private class mEngine extends Engine {
private final Handler handler = new Handler();
private final Runnable drawRunner = new Runnable() {
@Override
public void run() {
draw();
}
};
private Context context;
private Paint paint;
private boolean visible = true;
private boolean draw = true;
private int width, height;
private float scale;
private float begin_x, move_x;
private int touch_cnt = 0;
private int bg_max_x;
private Bitmap bg1, bg2, bg3, bg4..., bg20;
private float bg1_x, bg1_x2, bg2_x, bg3_x, bg4_x..., bg20_x;
private float bg1_y, bg2_y, bg3_y, bg4_y..., bg20_y;
private float bg2_pr, bg3_pr, bg3_pr..., bg20_pr;
private float bg1_offset_x, bg2_offset_x, bg3_offset_x, bg4_offset_x..., bg20_offset_x;
private long current_time;
private long last_update_time;
private Matrix sm;
Scroller mScroller;
public mEngine() {
context = getApplicationContext();
mScroller = new Scroller(context);
bg1 = getImage("bg1");
bg2 = getImage("bg2");
bg3 = getImage("bg3");
bg4 = getImage("bg4");
...
bg20 = getImage("bg20");
handler.post(drawRunner);
}
@Override
public void onVisibilityChanged(boolean visible) {
this.visible = visible;
if (visible) {
draw = true;
handler.post(drawRunner);
} else {
draw = false;
handler.removeCallbacks(drawRunner);
}
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
this.visible = false;
handler.removeCallbacks(drawRunner);
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (this.width != width && this.height != height) {
scale = (float) height / bg1.getHeight();
this.width = width;
this.height = height;
sm = new Matrix();
sm.setScale(scale, scale);
bg1 = resizeImage(bg1);
bg2 = resizeImage(bg2);
bg3 = resizeImage(bg3);
bg4 = resizeImage(bg4);
...
bg20 = resizeImage(bg20);
bg_max_x = bg1.getWidth() - width;
bg1_x = bg_max_x / 2;
bg1_y = 0;
#scroll_speed getting from preferences, 0.1f - 1f
scroll_length = bg_max_x * scroll_speed;
mScroller.setFinalX((int) bg1_x);
mScroller.abortAnimation();
bg2_pr = 0.2f;
bg2_offset_x = width / 2 - bg2.getWidth() / 2 + bg1_x * bg2_pr;
bg2_y = height - bg2.getHeight();
bg3_pr = 0.3f;
bg3_offset_x = width / 2 - bg3.getWidth() / 2 + bg1_x * bg3_pr;
bg3_y = height - bg3.getHeight();
bg4_pr = 0.4f;
bg4_offset_x = width / 2 - bg4.getWidth() / 2 + bg1_x * bg4_pr;
bg4_y = height - bg4.getHeight();
...
updatePosition();
}
super.onSurfaceChanged(holder, format, width, height);
}
private void updatePosition() {
bg2_x = bg2_offset_x - bg1_x * bg2_pr;
bg3_x = bg3_offset_x - bg1_x * bg3_pr;
bg4_x = bg4_offset_x - bg1_x * bg4_pr;
...
bg20_x = bg20_offset_x - bg1_x * bg20_pr;
}
@Override
public void onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
begin_x = event.getX();
move_x = 0;
touch_cnt = 0;
break;
case MotionEvent.ACTION_UP:
x = event.getX();
if (touch_cnt >= 1)
fling();
break;
case MotionEvent.ACTION_MOVE:
x = event.getX();
touch_cnt++;
//TODO drag
break;
}
}
private boolean fling() {
if (!mScroller.isFinished()) {
mScroller.forceFinished(true);
}
if (move_x != 0) {
bg1_x2 = mScroller.getCurrX() + move_x;
if (bg1_x2 <= 0) {
bg1_x2 = 0;
} else if (bg1_x2 > bg_max_x) {
bg1_x2 = bg_max_x;
}
if (bg1_x != bg1_x2) {
mScroller.fling(mScroller.getCurrX(), (int) bg1_y, -(int) (bg1_x > bg1_x2 ? 10000 : -10000), 0, mScroller.getCurrX() - scroll_length <= 0 ? 0 : (int) (mScroller.getCurrX() - scroll_length), mScroller.getCurrX() + scroll_length >= bg_max_x ? bg_max_x : (int) (mScroller.getCurrX() + scroll_length), 0, bg1.getHeight());
return true;
}
}
return false;
}
private void draw() {
current_time = System.currentTimeMillis();
if (mScroller.computeScrollOffset()) {
bg1_x = mScroller.getCurrX();
updatePosition();
draw = true;
}
if (draw && current_time - last_update_time >= 25) {
SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
c.drawBitmap(bg1, -bg1_x, bg1_y, null);
c.drawBitmap(bg2, bg2_x, bg2_y, null);
c.drawBitmap(bg3, bg3_x, bg3_y, null);
c.drawBitmap(bg4, bg4_x, bg4_y, null);
...
c.drawBitmap(bg20, bg20_x, bg20_y, null);
}
} finally {
if (c != null)
holder.unlockCanvasAndPost(c);
}
last_update_time = current_time;
draw = false;
}
handler.removeCallbacks(drawRunner);
if (visible) {
handler.postDelayed(drawRunner, 1);
}
}
private Bitmap resizeImage(Bitmap b) {
return Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), sm, true);
}
private Bitmap getImage(String n) {
File dir = context.getDir("theme", Context.MODE_PRIVATE);
File file = new File(dir, n + ".png");
if (file.exists()) {
return BitmapFactory.decodeFile(file.getAbsolutePath());
} else {
return BitmapFactory.decodeResource(getResources(), getResources().getIdentifier(n, "drawable", getPackageName()));
}
}
@Override
public void onDestroy() {
bg1.recycle();
bg2.recycle();
...
bg20.recycle();
}
}
}
MainActivity.java
import android.app.Activity;
import android.app.WallpaperManager;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
Intent service;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
service = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
service.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, new ComponentName(this, mWallpaperService.class));
service.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(service);
finish();
}
#button click
public void openService(View view) {
startActivity(service);
finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
答案 0 :(得分:2)
尝试Canvas.drawBitmap (Bitmap bitmap, null, Rect dst, Paint paint)
&#34; dst&#34;的大小rect将确定比例,将调整位图以适应它。这就是原生ImageView使用的内容,因此它应该非常快。
答案 1 :(得分:2)
看起来性能下降来自Bitmap.createBitmap(CPU调整大小)。我认为对于你的情况,没有理由使用Bitmap.createBitmap调整Bitmap的大小。相反,你应该通过GPU来实现。
调整大小的代码,Bitmap.createBitmap正在调整CPU位图大小:为新位图分配内存 - 从旧位图进行插值,填入新的位图 - 全部由CPU完成。
更好的方法是保持位图而不从CPU调整大小。相反,将整个位图加载到GPU中,并告诉GPU调整它的大小。例如,使用:
drawBitmap(位图位图,矩阵矩阵,油漆颜料)
使用指定的矩阵绘制位图。
您可以使用矩阵参数作为正在绘制的位图的调整大小矩阵。
最后,如果您有内存使用问题(例如,原始位图太大),您可以在将其加载到内存时将其缩小(使用Bitmap.createBitmap,CPU resize)一次。并且无需再次在onSurfaceChanged中调整大小(您可能需要重新计算调整大小矩阵)。
答案 2 :(得分:1)
如果我确实理解了您的问题,那么我认为此链接可能有所帮助:https://stackoverflow.com/a/4250279/2378691