// 2012.3.31
1【缓存 + 同步】确实是一种解决方案
但是我们会发现需要用这种方式的处理的地方很多,多线程下,需要保证线程安全的地方很多,这无疑给程序增加非常多的复杂度。
2 【缓存按键】
其实也可以反过来想想,在同一个线程里切换View,而可能发生View切换的地方其实是按键 onTouch()里,这时候我们需要处理的就是把按键缓存下来,然后在update()之前处理按键就行。
PS:当然一些非常耗时的操作还是需要另起线程,这个时候一般都需要一些变量来标示是否已加载完之类的。
实际用起来可以两者结合,缓存按键不够的话再加上 同步机制
目前我想到的解决线程不同步问题的方法:
I 条件判断
/** * 解决多线程切换View时线程不同步的问题 */ public static boolean hasInit; public GameView currentView; public void paint(Graphics g) { if(!hasInit) { return; } currentView.paint(g); } public void update() { if(!hasInit) { return; } currentView.update(); } public static boolean isRunning = true; public void run () { while (isRunning) { update(); paint(g); } } public void switchState(GameView view) { hasInit = false; // 释放上个View的资源 currentView.freeRes(); currentView = view; // load新View的资源 currentView.init(); hasInit = true; } public abstract class GameView { public abstract void init(); public abstract void freeRes(); public abstract void paint(Graphics g); public abstract void update(); }
多个线程访问switchState跳转状态时,主线程run还在跑,而另外一个线程跳转状态时会出现:
currentView.freeRes(); 当前资源已经释放,主线程却还在用的情况。
currentView.init();新的View还没初始化完,主线程却已经开始用。
用hasInit 来限制这段释放老资源load新资源的时间,比避免NullPointer的问题。
II 缓存机制
以上方法只是表面上可行,其实根本上并没有解决问题,只是在一定程度上降低了几率而已
/** * 缓存机制来 * 解决多线程切换View时线程不同步的问题 */ public void paint(Graphics g) { currentView.paint(g); } public void update() { currentView.update(); } public static boolean isRunning = true; public void run () { while (isRunning) { ViewManager.changeView(); update(); paint(g); } } /** * 界面基类 * @author wangxueping01 */ public abstract class GameView { public abstract void init(); public abstract void freeRes(); public abstract void paint(Graphics g); public abstract void update(); } /** * 界面管理 * @author wangxueping01 */ public class ViewManager { /** 当前的View */ public static GameView currentView; /** 缓存的View */ public static GameView cacheView; /** * 缓存跳转的状态View * @param view */ public static void switchView(GameView view) { cacheView = view; } /** * 每帧最开始调用 */ public static void changeView() { if (cacheView != null && cacheView != currentView) { currentView = cacheView; // 释放上个View的资源 currentView.freeRes(); currentView = view; // load新View的资源 currentView.init(); } cacheView = null; } }
switchView 和 changeView 应该是互斥的。但是对游戏来说,速度第一位。
目前采用第二种 同步机制需要进一步研究
III 同步机制
给互斥的方法加上synchronized
public class ViewManager { /** 当前的View */ public static GameView currentView; /** 缓存的View */ public static GameView cacheView; /** * 缓存跳转的状态View * @param view */ public static synchronized void switchView(GameView view) { cacheView = view; } /** * 每帧最开始调用 */ public static synchronized void changeView() { if (cacheView != null && cacheView != currentView) { currentView = cacheView; // 释放上个View的资源 currentView.freeRes(); currentView = view; // load新View的资源 currentView.init(); } cacheView = null; } }
synchronized