1

ビットマップが多くのメモリを使用しているというエラーが表示されます。

私はbitmap.recyle()を使うべきだと知っていますが、どこに置くべきかわかりません。どこに置いても、リサイクルされたビットマップを使おうとしているというエラーが表示されます。

誰かが助けることができればそれは素晴らしいことです。

これが私の関連コードです:

public class PictureViewer extends SherlockActivity implements
    android.view.GestureDetector.OnGestureListener {

private ViewFlipper viewFlipper = null;
private GestureDetector gestureDetector = null;
ArrayList<Integer> number = new ArrayList<Integer>();
DownloadBitmap bit = new DownloadBitmap();

int j = 1;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Remove title bar
    this.requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.pictureviewer);
    viewFlipper = (ViewFlipper) findViewById(R.id.viewflipper);
    gestureDetector = new GestureDetector(this);

    for (int i = 1; i <= 65; ++i)
        number.add(i);
    Collections.shuffle(number);

    loadImage();
    loadImage();
}

public void loadImage() {

    if (j == 65) { // Change this number to exact ammount of pictures
        j = 1;
    }
    int next = number.get(j);
    j++;

    ImageView image = new ImageView(this);
    Bitmap bitmap = bit.createBitmapFromUrl("http://comedyzone.mobi/img" + next + ".jpg");
    WeakReference<Bitmap> mBitmapReference = new WeakReference<Bitmap>(bitmap);
    image.setImageBitmap(mBitmapReference.get());
    image.setScaleType(ImageView.ScaleType.FIT_XY);
    viewFlipper.addView(image, new LayoutParams(LayoutParams.FILL_PARENT,
            LayoutParams.FILL_PARENT));
}

@Override
public boolean onDown(MotionEvent arg0) {
    // TODO Auto-generated method stub
    return false;
}

@Override
public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
        float arg3) {
    // TODO Auto-generated method stub
    if (arg0.getX() - arg1.getX() > 120) {

        this.viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
                R.anim.push_left_in));
        this.viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
                R.anim.push_left_out));
        this.viewFlipper.showNext();
        loadImage();
        return true;
    } else if (arg0.getX() - arg1.getX() < -120) {
        this.viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
                R.anim.push_right_in));
        this.viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
                R.anim.push_right_out));
        this.viewFlipper.showPrevious();
        loadImage();
        return true;
    }
    return true;
}

@Override
public void onLongPress(MotionEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
        float arg3) {
    // TODO Auto-generated method stub
    return false;
}

@Override
public void onShowPress(MotionEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public boolean onSingleTapUp(MotionEvent arg0) {
    // TODO Auto-generated method stub
    return false;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    return this.gestureDetector.onTouchEvent(event);
}

private InputStream OpenHttpConnection(String urlString) throws IOException {
    InputStream in = null;
    int response = -1;

    URL url = new URL(urlString);
    URLConnection conn = url.openConnection();

    if (!(conn instanceof HttpURLConnection))
        throw new IOException("Not an HTTP connection");

    try {
        HttpURLConnection httpConn = (HttpURLConnection) conn;
        httpConn.setAllowUserInteraction(false);
        httpConn.setInstanceFollowRedirects(true);
        httpConn.setRequestMethod("GET");
        httpConn.connect();

        response = httpConn.getResponseCode();
        if (response == HttpURLConnection.HTTP_OK) {
            in = httpConn.getInputStream();
        }
    } catch (Exception ex) {
        throw new IOException("Error connecting");
    }
    return in;
}
4

5 に答える 5

6

私はbitmap.recyle()を使用する必要があることを知っています

電話をかけるrecycle必要はありません。

昨年のGoogleIOで、このトピックについて正確に話がありました。

Google I / O 2011:Androidアプリのメモリ管理-これらすべてを確実に監視する必要があります。時間の価値があります。

WeakReferenceオブジェクトを作成することは、より良い管理Bitmapに向けた良いスタートです。Bitmap例えば:

Bitmap bitmap = DownloadImage("http://comedyzone.mobi/img" + next + ".jpg");
WeakReference<Bitmap> mBitmapReference = new WeakReference<Bitmap>(bitmap);
image.setImageBitmap(mBitmapReference.get());

ビットマップを効率的に表示する

これらは、あなたも読むべきAndroidトレーニングクラスです。

また、これは私がURLから画像をダウンロードするために書いたクラスです。メソッドの代わりに使用することを検討する必要がありますDownloadImage。はるかに効率的です。

DownloadBitmap

public class DownloadBitmap {

private static String LOG_TAG = DownloadBitmap.class.getName();

/**
 * @param url
 * @return Bitmap image from the interwebs
 */
static Bitmap createBitmapFromUrl(String url) {
    final Bitmap mBitmap = readBitmapFromNetwork(url);
    final WeakReference<Bitmap> mBitmapReference = new WeakReference<Bitmap>(mBitmap);
    if (mBitmapReference.get() != null)
        return mBitmapReference.get();
    return null;
}

/**
 * @param urlString The URL to read the bitmap from.
 * @return A Bitmap image or null if an error occurs.
 */
private static Bitmap readBitmapFromNetwork(String urlString) {
    InputStream mInputStream = null;
    FlushedInputStream mFlushedInputStream = null;
    Bitmap mBitmap = null;
    WeakReference<Bitmap> mBitmapReference = null;
    try {
        final BitmapFactory.Options mOptions = new BitmapFactory.Options();
        mOptions.inPurgeable = true;
        mOptions.inDither = false;
        final URL mUrl = new URL(urlString);
        final URLConnection mConnection = mUrl.openConnection();
        mConnection.connect();
        mInputStream = mConnection.getInputStream();
        mFlushedInputStream = new FlushedInputStream(mInputStream);
        mBitmap = BitmapFactory.decodeStream(mFlushedInputStream, null, mOptions);
        mBitmapReference = new WeakReference<Bitmap>(mBitmap);
    } catch (MalformedURLException e) {
        if (BuildConfig.DEBUG)
            Log.e(LOG_TAG, "Bad image URL", e);
        return null;
    } catch (IOException e) {
        if (BuildConfig.DEBUG)
            Log.e(LOG_TAG, "Could not get remote image", e);
        return null;
    } finally {
        try {
            if (mInputStream != null)
                mInputStream.close();
            if (mFlushedInputStream != null)
                mFlushedInputStream.close();
        } catch (IOException e) {
            if (BuildConfig.DEBUG)
                Log.e(LOG_TAG, "Error closing stream.");
            return null;
        }
    }
    if (mBitmapReference.get() != null)
        return mBitmapReference.get();
    return null;
}

/**
 * An InputStream that skips the exact number of bytes provided, unless it
 * reaches EOF.
 */
static class FlushedInputStream extends FilterInputStream {
    public FlushedInputStream(InputStream inputStream) {
        super(inputStream);
    }

    @Override
    public long skip(long n) throws IOException {
        long totalBytesSkipped = 0L;
        while (totalBytesSkipped < n) {
            long bytesSkipped = in.skip(n - totalBytesSkipped);
            if (bytesSkipped == 0L) {
                int bytes = read();
                if (bytes < 0) {
                    break;
                } else {
                    bytesSkipped = 1;
                }
            }
            totalBytesSkipped += bytesSkipped;
        }
        return totalBytesSkipped;
    }
  }
}
于 2012-07-13T04:37:51.827 に答える
1

ビットマップを使用する前に、サンプルサイズを小さくする必要があります。これを使用してこれを行うことができます。

 private Bitmap decodeFile(File file)
{
    try 
    {
        //********************* decode image size ********************
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(file), null, options);

        // ********************** Find the correct scale value. It should be the power of 2. ********************
        options.inSampleSize = BitmapConverter.calculateInSampleSize(options, 145, 105);
        options.inJustDecodeBounds = false;

        return BitmapFactory.decodeStream(new FileInputStream(file), null, options);
    } 
    catch(FileNotFoundException eFileNotFoundException) 
    {

        return null;
    }
}

そして、必要に応じてBitmap.recycle()を呼び出すことができますが、必要ではないと思います。

于 2012-07-13T05:02:20.287 に答える
0

このステートメントの後にビットマップは不要になったため、関数内のbitmap.recycle()このステートメントの直後に書き込むことができます。image.setImageBitmap(bitmap);loadImage()

このエラーは、非常に大きなサイズのビットマップを使用したか、コードにメモリリークがあるために発生します。

ビットマップを使用するときは常に、可能な限りすべてのオプションを使用して、可能な限り最小限のメモリを使用するようにしてください。

詳細については、同じ問題に関する私の回答を参照してください。

于 2012-07-13T04:33:59.893 に答える
0

ImageLoader
画像をバックグラウンドでロードするImageloaderクラスを使用できます。
イメージローダー

于 2012-07-13T04:24:35.287 に答える
0

一般的に言えば、オブジェクトが不要になったときにクリーンアップするためにオブジェクトにマークを付ける必要があります。あなたの状況では、これらのビットマップが不要になるのは、アクティビティが最前線でなくなったときだけです。

私が見ているのは、ViewFlipperで不必要に大きなビットマップが使用される可能性があることです。追加後にImageViewのサイズを変更するのではなく、ImageView内に設定する前にビットマップのサイズを変更する必要があります。BitmapFactoryのオプションとしてinSampleSizeを使用し、ImageViewにロードする前にBitmap.createScaledBitmap()でビットマップのサイズを変更してみてください。

于 2012-07-13T05:35:40.223 に答える