Android开发中如何让多个类访问同一个类实例?
解决多类共享同一实例的问题
嘿,我完全懂你的困扰——你想让GameView负责绘制炮塔,Logic负责更新它的位置,两者共用同一个炮塔实例,而不是各自创建新的,对吧?这在游戏开发里是非常常见的需求,咱们用两种实用的方法来解决它:
方法一:构造函数传递实例(推荐,灵活可控)
这种方法最直观,也最适合游戏场景(毕竟你可能以后会有多个炮塔实例)。核心思路是:在统一的入口处创建炮塔实例,然后把这个实例传递给需要它的GameView和Logic。
步骤1:修改GameView,接收外部传入的炮塔实例
原来的GameView里自己没初始化simpleTurret,直接调用会空指针,咱们改成从外部接收:
public class GameView extends SurfaceView implements Runnable { private boolean running = true; SurfaceHolder surfaceHolder = getHolder(); SimpleTurret simpleTurret; // 构造函数新增SimpleTurret参数 public GameView (Context context, SimpleTurret turret){ super(context); this.simpleTurret = turret; // 绑定外部传入的共享实例 Thread thread = new Thread(this); thread.start(); } @Override public void run() { while (running){ DrawCanvas(); // 加个小延时,避免线程占用过高CPU try { Thread.sleep(16); // 对应约60帧/秒的刷新频率 } catch (InterruptedException e) { e.printStackTrace(); } } } public void DrawCanvas(){ Canvas canvas = surfaceHolder.lockCanvas(); if (surfaceHolder.getSurface().isValid()){ canvas.drawColor(Color.RED); // 现在simpleTurret已经有实例了,不会空指针 canvas.drawBitmap(simpleTurret.getSprite(), simpleTurret.getX(), simpleTurret.getY(), null); surfaceHolder.unlockCanvasAndPost(canvas); } } }
步骤2:修改Logic,同样接收共享实例
原来的Logic里自己创建了新的SimpleTurret,现在改成接收外部实例:
public class Logic implements Runnable{ Boolean isRunning; private Thread logicThread; SimpleTurret simpleTurret; // 构造函数新增SimpleTurret参数 public Logic(Context context, boolean running, SimpleTurret turret){ this.simpleTurret = turret; // 绑定同一个共享实例 logicThread = new Thread(this); logicThread.start(); isRunning = running; } @Override public void run() { while (isRunning){ simpleTurret.isMoving(); // 直接操作共享实例更新位置 // 同样加延时,和绘制线程频率匹配 try { Thread.sleep(16); } catch (InterruptedException e) { e.printStackTrace(); } } } }
步骤3:在入口处创建实例并传递
比如在你的MainActivity里(或者其他初始化游戏的地方),统一创建炮塔实例,再传给两个类:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 创建唯一的炮塔实例 SimpleTurret sharedTurret = new SimpleTurret(this); // 把实例传给GameView和Logic GameView gameView = new GameView(this, sharedTurret); Logic gameLogic = new Logic(this, true, sharedTurret); setContentView(gameView); }
方法二:单例模式(适合全局唯一的炮塔)
如果你确定整个游戏里只会有一个SimpleTurret,那可以用单例模式,让它全局只有一个实例,任何类都能直接获取。
修改SimpleTurret为单例类
public class SimpleTurret extends Turrets { // 静态变量存储唯一实例 private static SimpleTurret instance; // 私有构造函数,禁止外部直接new private SimpleTurret(Context context){ super(context); sprite = BitmapFactory.decodeResource(context.getResources(), R.drawable.test_sprite); health = 50; x = 300; y = 100; speed = 1; } // 全局获取实例的方法,确保只有一个实例 public static synchronized SimpleTurret getInstance(Context context){ if (instance == null){ // 用ApplicationContext避免内存泄漏 instance = new SimpleTurret(context.getApplicationContext()); } return instance; } }
在GameView和Logic中获取单例
// GameView的构造函数里 public GameView (Context context){ super(context); // 获取全局唯一的炮塔实例 simpleTurret = SimpleTurret.getInstance(context); Thread thread = new Thread(this); thread.start(); } // Logic的构造函数里 public Logic(Context context, boolean running){ // 获取同一个全局实例 simpleTurret = SimpleTurret.getInstance(context); logicThread = new Thread(this); logicThread.start(); isRunning = running; }
额外注意事项
- 空指针问题:你原来的代码里
GameView的simpleTurret和rapidFireTurret都没初始化,直接调用方法会崩溃,上面的两种方法都解决了这个问题。 - 线程安全:多线程操作同一个实例时,要注意变量的线程安全(比如炮塔的
x、y可以用volatile修饰,或者用同步块)。 - 内存泄漏:单例模式里一定要用
ApplicationContext,不要用Activity的Context,否则会导致Activity无法被回收。
内容的提问来源于stack exchange,提问作者Frenchie
相关产品推荐
相关产品推荐

