android缩放位图的性能

我有这个:

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; } } 

我正在调整图像的大小,而不是更小。

  1. 没有调整,效果很好,performance100%

    bitmap1 = getImage("bitmap1"); ... bitmap20 = getImage("bitmap20");

  2. resize,performance80%

    bitmap1 = getImage("bitmap1"); ... bitmap20 = getImage("bitmap20");

    called once, when screen width and height are known bitmap1 = resizeImage(bitmap1); ... bitmap20 = resizeImage(bitmap20);

  3. 没有resize,canvas比例,performance40%

    bitmap1 = getImage("bitmap1"); ... bitmap20 = getImage("bitmap20");

    set canvas.scale(scale, scale) inside draw() method

我知道有一些像libgdx这样的框架调整图像大小,而不会丢失性能,但我使用本地canvas。

问题 :如何绘制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(); } } 

Solutions Collecting From Web of "android缩放位图的性能"

试试Canvas.drawBitmap (Bitmap bitmap, null, Rect dst, Paint paint)

“dst”矩形的大小将决定比例,位图将被调整以适应其内部。 这就是本机ImageView使用的,所以它应该是非常快的。

看起来性能下降来自Bitmap.createBitmap(调整CPU大小)。 我认为你的情况没有理由调整位图使用Bitmap.createBitmap。 相反,你应该通过GPU做到这一点。

resize的代码Bitmap.createBitmap正在执行CPU位图resize:为新的位图分配内存 – 从旧的位图进行插值,填充到新的位图 – 全部由CPU完成。

更好的方法是保持位图不从CPUresize。 相反,将整个位图加载到GPU中,并告诉GPU调整它的大小。 例如,使用:

drawBitmap(位图位图,matrixmatrix,Paint paint)

使用指定的matrix绘制位图。

您可以使用matrix参数作为正在绘制的位图的resizematrix。

最后,如果你有内存使用的问题(例如,原来的位图太大),你可以缩小它(使用Bitmap.createBitmap,CPUresize)一次,当你加载到内存中。 并且不需要在onSurfaceChanged中重新resize(尽pipe您可能需要重新计算大小调整matrix)。

如果我理解你的问题,那么我认为这个链接可能有所帮助: https : //stackoverflow.com/a/4250279/2378691