很多drawBitmap之后,图像质量变差了

时间:2011-07-17 11:45:27

标签: java android live-wallpaper android-canvas

我的程序在动态壁纸画布上绘制位图。 它有效,但一段时间后图像变得非常糟糕(http://img855.imageshack.us/img855/9756/deviceq.png

任何想法为什么?

package com.tripr;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Paint.Align;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;



/*
 * This animated wallpaper draws a rotating wireframe cube.
 */
public class MyWallpaperService extends WallpaperService{

    private final String TAG = "tripr";



    @Override
    public void onCreate() {
        super.onCreate();

    }

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

    @Override
    public Engine onCreateEngine() {
        return new CubeEngine(this);
    }


    class CubeEngine extends Engine  implements LocationListener{

        private MyWallpaperService mws;
        private float xOffset;
        private float xStep;
        private int xPixels;
        private String lastPhotoUrl = "";
        private LocationManager lm;
        private Bitmap bmp = null;
        private String locationName;
        private String status = "waiting for location update...";
        private final Handler mHandler = new Handler();

        private final Runnable mDrawBtmp = new Runnable() {
            public void run() {
                drawFrame();
            }
        };
        private boolean mVisible;


        CubeEngine(MyWallpaperService mymws) {
            mws = mymws;

            lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
            requestLocationUpdates();
            MyThread myThread = new MyThread(lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER));
            myThread.start();
        }


        //taken from http://p-xr.com/android-tutorial-how-to-parse-read-json-data-into-a-android-listview/
        private JSONObject getJSONfromURL(String url){

            //initialize
            InputStream is = null;
            String result = "";
            JSONObject jArray = null;

            //http post
            try{
                HttpClient httpclient = new DefaultHttpClient();
                HttpGet httpget = new HttpGet(url);
                HttpResponse response = httpclient.execute(httpget);
                HttpEntity entity = response.getEntity();
                is = entity.getContent();

            }catch(Exception e){
                Log.e(TAG, "Error in http connection "+e.toString());
            }

            //convert response to string
            try{
                BufferedReader reader = new BufferedReader(new InputStreamReader(is,"iso-8859-1"), 8);
                StringBuilder sb = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }
                is.close();
                result=sb.toString();
            }catch(Exception e){
                Log.e(TAG, "Error converting result "+e.toString());
            }

            //try parse the string to a JSON object
            //Log.d(TAG, result);
            try{
                    jArray = new JSONObject(result);
            }catch(JSONException e){
                Log.e(TAG, "Error parsing data "+e.toString());
            }

            return jArray;
        }


        String getFlickrUrl(double lat, double lon, double radius){
            return "http://api.flickr.com/services/rest/?" +
                    "method=flickr.photos.search" +
                    "&api_key=a6d9db5ff2885dd2f8949590e7a44762" +
                    "&tags=architecture" +
                    "&lat=" + lat +
                    "&lon=" + lon +
                    "&radius=" + radius +
                    "&radius_units=km" +
                    "&extras=geo%2Curl_z%2Ctags" +
                    "&per_page=250" +
                    "&format=json" +
                    "&sort=interestingness-desc" +
                    "&nojsoncallback=1";
        }


        void requestLocationUpdates(){
            if (!(lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER))){
                status = "locating over network disabled";
                //bmp = null;
            }
            lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000*30, 10, this);
        }

        void removeUpdates(){
            lm.removeUpdates(this);
        }


        @Override
        public void onLocationChanged(Location location) {
            MyThread myThread = new MyThread(location);
            myThread.start();

        }

        @Override
        public void onProviderDisabled(String provider) {}

        @Override
        public void onProviderEnabled(String provider) {}

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {}


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

        @Override
        public void onVisibilityChanged(boolean visible) {
            mVisible = visible;
            if (visible) {
                requestLocationUpdates();
                drawFrame();
            } else {
                mHandler.removeCallbacks(mDrawBtmp);
                removeUpdates();
            }
        }

        @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(mDrawBtmp);
        }

        @Override
        public void onOffsetsChanged(float xOffset, float yOffset,
                float xStep, float yStep, int xPixels, int yPixels) {
            /*Log.d(TAG, "onOffsetsChanged");
            Log.d(TAG, "xOffset: " + String.valueOf(xOffset));
            Log.d(TAG, "yOffset: " + String.valueOf(yOffset));
            Log.d(TAG, "xStep: " + String.valueOf(xStep));
            Log.d(TAG, "yStep: " + String.valueOf(yStep));
            Log.d(TAG, "xPixels: " + String.valueOf(xPixels));
            Log.d(TAG, "yPixels: " + String.valueOf(yPixels));
            //Log.d(TAG, String.valueOf((xOffset / xStep)));
            Log.d(TAG, " ");*/

            this.xPixels = xPixels;
            this.xStep = xStep;
            this.xOffset = xOffset;
            drawFrame();
        }

        /*
         * Store the position of the touch event so we can use it for drawing later
         */
        @Override
        public void onTouchEvent(MotionEvent event) {
            super.onTouchEvent(event);
        }

        /*
         * Draw one frame of the animation. This method gets called repeatedly
         * by posting a delayed Runnable. You can do any drawing you want in
         * here. This example draws a wireframe cube.
         */
        void drawFrame() {
            final SurfaceHolder holder = getSurfaceHolder();

            Canvas c = null;
            try {
                c = holder.lockCanvas();
                if (c != null) {
                    // draw something
                    drawBmp(c);
                }
            } finally {
                if (c != null) holder.unlockCanvasAndPost(c);
            }

            // Reschedule the next redraw
            mHandler.removeCallbacks(mDrawBtmp);
            if (mVisible) {
                mHandler.postDelayed(mDrawBtmp, 1000 / 5);
            }
        }

        private class MyThread extends Thread {
            Location loc;

            MyThread(Location loc){
                this.loc = loc;
            }

            public synchronized void run(){ // bringt synchronized was? weil wir kreieren ja immer eine neue intanz...

                    try{

                        if (loc == null){
                            Log.d(TAG, "location is null");
                            return;
                        }


         <SNIP>
         //the main code, update `status` and `bmp`
        }

        void drawBmp(Canvas canvas) {
            //canvas.restore();
            //canvas.save();
            //canvas.translate(0, 0);
            //canvas.drawColor(0xff00aa00);
            canvas.drawColor(Color.BLACK);

            if (bmp != null){
                //int width = (int) (((double)bmp.getHeight()/(double)canvas.getHeight())*canvas.getWidth());
                if (bmp.getHeight() != canvas.getHeight()){
                    Float width  = new Float(bmp.getWidth());
                    Float height = new Float(bmp.getHeight());
                    Float ratio = width/height;
                    Log.d(TAG, "scaling");
                    bmp = Bitmap.createScaledBitmap(bmp, (int)(canvas.getHeight()*ratio), canvas.getHeight(), true);
                }


                int x;
                if (bmp.getWidth() >= canvas.getWidth()){
                    x = -1*(int)((xOffset*(bmp.getWidth()-canvas.getWidth())));
                }else{
                    x = (bmp.getWidth()-canvas.getWidth())/2;
                }
                //Log.d(TAG,  String.valueOf(scale));
                //Log.d(TAG,  String.valueOf(canvas.getWidth()));
                //Log.d(TAG, " ");
                canvas.drawBitmap(bmp, x, 0, null);


                //canvas.drawLine(0, 0, bmp.getWidth(), 0, new Paint());

            }else if(status != null){
                Paint textPaint = new Paint();
                textPaint.setColor(Color.WHITE);
                textPaint.setAntiAlias(true);
                textPaint.setTextSize(25);
                textPaint.setAlpha(120);
                textPaint.setTextAlign(Align.CENTER);
                canvas.drawText(status, canvas.getWidth()/2, canvas.getHeight()/2, textPaint);
            }
            if (locationName != null){
                Paint textPaint = new Paint();
                textPaint.setColor(Color.BLACK);
                textPaint.setAntiAlias(true);
                textPaint.setTextSize(30);
                textPaint.setAlpha(150);
                textPaint.setTextAlign(Align.LEFT);
                Rect rect = new Rect();
                textPaint.getTextBounds(locationName, 0, locationName.length(), rect);
                //Log.d(TAG, String.valueOf(textPaint.getTextSize()));
                canvas.drawText(locationName, 0, 70, textPaint);
            }

        }
    }
}

1 个答案:

答案 0 :(得分:3)

drawBmp()中,您反复拍摄位图(bmp),将其缩放(调用createScaledBitmap),然后将其分配回bmp。随着时间的推移,所有这些缩放操作都将导致您看到的工件。

要解决此问题,请将原始位图存储在其他变量(例如private Bitmap originalImage;)中,并从原始位图创建缩放位图。

bmp = Bitmap.createScaledBitmap(originalImage, (int)(canvas.getHeight()*ratio), canvas.getHeight(), true);