Aharon Manne
Aharon Manne

Reputation: 712

Changing reference to object causes previous object data to be overwritten

I seem to have a problem with references to java objects, probably as a result of years of programming in C. The following code is supposed to enable me to move objects of "WordPart" around a canvas. When I choose the first object, it moves as expected. When I release the first object, and choose the second, the location of of both the first and the second objects becomes identical. (I have removed code needed for compilation, but irrelevant to the question.) As far as I can tell, the activeImage reference seems to point to both objects in the wordPartList simultaneously. Please help me find my misunderstanding.

...
public class ONG2Activity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new SurfaceView2(this));
}

public class SurfaceView2 extends SurfaceView implements SurfaceHolder.Callback {    

ArrayList<WordParts> wordPartList;
WordParts activeImage;
Point activePosition;
String TAG = "SurfaceView2";
public SurfaceView2(Context context) {
super(context);        
wordPartList = NewPartList(context);
this.getHolder().addCallback(this);
setFocusable(true);
activeImage = null;
activePosition = new Point();
}
/**
 * 
 * @return list of word parts
 */
private ArrayList<WordParts> NewPartList(Context context) {
ArrayList<WordParts> newParts = new ArrayList<WordParts>();
newParts.add(new WordParts(context, new Point(400, 100), "foo"));
newParts.add(new WordParts(context, new Point(200, 100), "bar");
return newParts;
}
@Override
protected void onDraw(Canvas canvas) {
Log.d(TAG, "inside onDraw");
canvas.drawColor(Color.BLACK);
if (activeImage != null) {
activeImage.NewPosition(activePosition);
}
draw(canvas, BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher), new Point(100, 300));
draw(canvas, BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher), new Point(200, 300));
draw(canvas, BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher), new Point(300, 300));
for (WordParts wp : wordPartList) {
Point center = wp.getCenter();
Log.d(TAG, String.format("Word part %s at x=%d, y=%d", wp.mWordPartString, center.x, center.y));
draw(canvas, wp.getBitMap(), center);
}

}     
@Override    
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG, String.format("inside on touch, event is %s", event.toString()));
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
// if within wordPart, set as active
for (WordParts wp : wordPartList) {
if (wp.isInside(event)) {
activeImage = wp;
Log.d(TAG, String.format("Touch down inside word part %s", wp.mWordPartString));
break; // end iteration
}
}

break;
case MotionEvent.ACTION_UP:
for (WordParts wp : wordPartList) {
if (activeImage == wp){
wp.endTouch();
Log.d(TAG, String.format("Released word part %s", wp.mWordPartString));
}
}
activeImage = null;
break;

default:
break;
}
activePosition.x = (int) event.getX();
activePosition.y = (int) event.getY();
if (activeImage != null)
this.postInvalidate(); // force call to onDraw
return true;
}

/**
 * Draw the bitmap centered at specified point
 * @param canvas - target of drawing
 * @param bm - bitmap to draw
 * @param centerPt
 */
public void draw(Canvas canvas, Bitmap bm, Point centerPt) {
canvas.drawBitmap( bm, 
   centerPt.x - (bm.getWidth() / 2), 
   centerPt.y - (bm.getHeight() / 2), null); 
Log.d(TAG, String.format("canvas %s, bm %s, point %s", canvas.toString(), bm.toString(), centerPt.toString()));
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) 
{     

}
public void surfaceCreated(SurfaceHolder holder) {
Log.d("surface", "Surface created");        
setWillNotDraw(false);
            }
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d("surface", "Surface destroyed");
}
}
}

Upvotes: 1

Views: 88

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1499740

I suspect this is the problem:

if (activeImage != null) {
    activeImage.NewPosition(activePosition);
}

Unfortunately we don't have the code for unconventionally-named NewPosition, but presumably it sets the value of a field in a WordParts. If you set the value of two fields within two separate WordParts objects to refer to the same Point, then later when you change the values within that Point like this:

activePosition.x = (int) event.getX();
activePosition.y = (int) event.getY();

then yes, those changes will be visible via both WordParts objects, as they both refer to the same object.

If you're new to Java, I would strongly advise you to learn the basics of the language through simple console apps. Learn about objects, references and primitives, inheritance, the core collections and IO etc, then start working in the trickier environment of UIs and mobile.

Upvotes: 3

Related Questions