2

我试图在另一个线程中从磁盘加载图像,以免减慢我的绘制线程,但问题是当保存位图的对象被传输到新线程时,它们有不同的指针。我不完全确定Java如何跨可乘线程处理指针,但我正在寻找一种解决方案,使两个线程都使用同一个对象(浅拷贝)而不是线程之间对象的深度拷贝。

这是我的代码

new LoadImageTask().execute(ThisTimeDrawBitmaps.indexOf(bitmapWrapper), gameEngine);

private class LoadImageTask extends AsyncTask {
    protected BitmapWrapper LoadImage(BitmapWrapper bitmapWrapper, GameEngine gameEngine) {
        //loading the image in a temp object to avoid  fatal error 11
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inScaled = true;
        Bitmap tempImage = BitmapFactory.decodeResource(Sceptrum.GetResources, bitmapWrapper.getID(), options);
        tempImage = Bitmap.createScaledBitmap(bitmapWrapper.getBitmap(), (int) (bitmapWrapper.getBitmap().getWidth() * gameEngine.getScale()), (int) (bitmapWrapper.getBitmap().getHeight() * gameEngine.getScale()), false);
        //so that the image can be gc.
        Bitmap RemovePointer = bitmapWrapper.getBitmap();
        //to avoid fatal error 11
        bitmapWrapper.setBitmap(tempImage);
        //removing the old image.
        RemovePointer.recycle();
        return bitmapWrapper;
     }
    @Override
    /**
     * add the bitmapwrapper you want to load and make sure to add the GameEngine as the last parameter.
     */
    protected Object doInBackground(Object... params) {
        for (int i = 0; i < params.length - 1; i++) {
            return LoadImage(ThisTimeDrawBitmaps.get((Integer) params[i]), (GameEngine) params[params.length - 1]);
        }
        return null;
    }
 }

public class BitmapWrapper{
private Bitmap bitmap;
/**
 * Use only to send the bitmap as a parameter. To modify or read data to/from the bitmap use the methods provided by BitmapWrapper.
 * @return
 */
public Bitmap getBitmap() {
    return bitmap;
}
public void setBitmap(Bitmap bitmap) {
    this.bitmap = bitmap;
}
private int id;
public int getID()
{
    return id;
}
private Point originalSize;
public Point getOriginalSize() {
    return originalSize;
}
public BitmapWrapper(Bitmap bitmap, int ID) {
    this.setBitmap(bitmap);
    id = ID;
    originalSize = new Point(bitmap.getWidth(), bitmap.getHeight());
}
public int getWidth()
{
    return bitmap.getWidth();
}
public int getHeight()
{
    return bitmap.getHeight();
}
public void createScaledBitmap(GameEngine gameEngine)
{
    bitmap = Bitmap.createScaledBitmap(bitmap, (int) (originalSize.x * gameEngine.getScale()), (int) (originalSize.y * gameEngine.getScale()), false);
}
public void CreateBitmap()
{
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inScaled = false;
    bitmap = BitmapFactory.decodeResource(Sceptrum.GetResources, id, options);
}
}
4

3 回答 3

7

这不是指针问题(Java 中确实存在这样的问题:))。如果您想在后台线程中加载图像,您应该创建一个(静态)AsyncTask,它持有对布局中视图的弱引用,您实际上希望在其中放置位图。在 doInBackground 中,您应该加载图像并返回它们。在 postExecute(在 UI 线程上调用)中,您将收到 doInBackground(位图)的结果。检查引用的视图是否仍然存在(活动仍然存在)后,您可以使用位图(将它们放在视图中)。

您不能从任何其他线程修改 UI 元素,除了 UI 线程(这适用于任何 UI 框架)。

于 2013-02-22T09:33:48.133 回答
0

您可以尝试使用volatile. 我是说:

private volatile Bitmap bitmap;

“声明为 volatile 的变量必须在所有线程中同步其数据”来自:http ://www.javaperformancetuning.com/news/qotm030.shtml

于 2013-02-20T20:44:30.397 回答
0

尝试引入一个Container对象。

public class Container<T> {
    private volatile boolean ready = false;
    private T object;

    public boolean isReady() { 
        return ready; 
    }

    public void setReady(boolean ready) {
        this.ready = ready;
    }

    public T get() {
        return (ready) ? object : null;
    }

    public void set(T object) {
        this.object = object;
    }
}

你可以用任何类型实例化这个容器:

Container<Bitmap> logoContainer = new Container<Bitmap>();
Bitmap logo = logoContainer.get(); // returns null if not yet ready

在后台线程中,您可以初始化:

Container<Bitmap> logoContainer = ... // 
Bitmap b = ... // load
logoContainer.set(b);
logoContainer.setReady(true);
于 2013-02-21T16:11:56.163 回答