我正在使用自定义SurfaceView类来尝试在屏幕上绘制位图。此外,我正在使用导航抽屉和片段来切换显示哪个SurfaceView。我知道这个部分正在工作,因为我为每个部分设置了不同的背景颜色,我看到了颜色的变化。问题是从不调用surfaceCreated()。我在该方法中为SurfaceView启动绘图线程,因此线程永远不会启动,并且永远不会绘制位图。
以下是我的主要活动中与片段切换相关的部分:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_screen);
}
private void selectItem(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
if(position ==0) {
fragment = new MapFragment();
} else {
fragment = new TempFragment();
}
Bundle args = new Bundle();
args.putInt(MapFragment.ARG_PLANET_NUMBER, position);
fragment.setArguments(args);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.container, fragment).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(appScreens[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
public static class MapFragment extends Fragment {
public static String ARG_PLANET_NUMBER = "planet_number";
public MapFragment() {
// Empty constructor required for fragment subclasses
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_map_screen, container, false);
MapSurfaceView bmpView = (MapSurfaceView) rootView.findViewById(R.id.bmpView);
bmpView.setMap(map);
return rootView;
}
}
注意:MapFragment和TempFragment的背景颜色不同。
主要活动布局:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- As the main content view, the view below consumes the entire
space available using match_parent in both dimensions. -->
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
If you're not building against API 17 or higher, use
android:layout_gravity="left" instead. -->
<!-- The drawer is given a fixed width in dp and extends the full height of
the container. -->
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:background="#cccc" />
</android.support.v4.widget.DrawerLayout>
SurfaceView:
class MapSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
class MapThread extends Thread {
private Context mContext;
/**
* Handle to the surface manager object we interact with
*/
private SurfaceHolder mSurfaceHolder;
/*
* State-tracking constants
*/
public static final int STATE_PAUSE = 1;
public static final int STATE_RUNNING = 2;
/**
* The state of the game. One of READY, RUNNING, PAUSE, LOSE, or WIN
*/
private int mMode;
/**
* Indicate whether the surface has been created & is ready to draw
*/
private boolean mRun = false;
public MapThread(SurfaceHolder surfaceHolder, Context context) {
// get handles to some important objects
mSurfaceHolder = surfaceHolder;
mContext = context;
}
/**
* Starts the game, setting parameters for the current difficulty.
*/
public void doStart() {
synchronized (mSurfaceHolder) {
setState(STATE_RUNNING);
}
}
/**
* Pauses the physics update & animation.
*/
public void pause() {
synchronized (mSurfaceHolder) {
if (mMode == STATE_RUNNING) setState(STATE_PAUSE);
}
}
/**
* Restores game state from the indicated Bundle. Typically called when
* the Activity is being restored after having been previously
* destroyed.
*
* @param savedState Bundle containing the game state
*/
public synchronized void restoreState(Bundle savedState) {
synchronized (mSurfaceHolder) {
setState(STATE_PAUSE);
}
}
@Override
public void run() {
while (mRun) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
if (mMode == STATE_RUNNING)
doDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
/**
* Dump game state to the provided Bundle. Typically called when the
* Activity is being suspended.
*
* @return Bundle with this view's state
*/
public Bundle saveState(Bundle map) {
synchronized (mSurfaceHolder) {
}
return map;
}
/**
* Used to signal the thread whether it should be running or not.
* Passing true allows the thread to run; passing false will shut it
* down if it's already running. Calling start() after this was most
* recently called with false will result in an immediate shutdown.
*
* @param b true to run, false to shut down
*/
public void setRunning(boolean b) {
mRun = b;
}
/**
* Sets the game mode. That is, whether we are running, paused, in the
* failure state, in the victory state, etc.
*
* @param mode one of the STATE_* constants
*/
public void setState(int mode) {
synchronized (mSurfaceHolder) {
mMode = mode;
}
}
/**
* Resumes from a pause.
*/
public void unpause() {
// Move the real time clock up to now
synchronized (mSurfaceHolder) {
}
setState(STATE_RUNNING);
}
/**
* Draws the ship, fuel/speed bars, and background to the provided
* Canvas.
*/
private void doDraw(Canvas canvas) {
Bitmap mapBMP = map.getMapBitmap().copy(Bitmap.Config.ARGB_8888, true);
//System.out.println(mapBMP.describeContents());
canvas.setBitmap(mapBMP);
}
}
private Map map = null;
private Context mContext;
private MapThread thread;
private Object mPauseLock;
private boolean mPaused;
private boolean mFinished;
private boolean running = false;
public MapSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
// create thread only; it's started in surfaceCreated()
thread = new MapThread(holder, context);
setFocusable(true);
}
public MapThread getThread(){
return thread;
}
public void setMap(Map map) {
this.map = map;
}
public void onFinishInflate() {
System.out.println("Inflated");
}
public void onAttachedToWindow(){
System.out.println("Attached");
}
public void onDetachedFromWindow(){
System.out.println("Detached");
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
if (!hasWindowFocus) thread.pause();
else thread.unpause();
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
System.out.println("Surface created");
thread.setRunning(true);
thread.start();
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}
SurfaceView布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.wrathfulape.supremacy.MainScreen$PlaceholderFragment">
<com.wrathfulape.supremacy.MapSurfaceView
android:id="@+id/bmpView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>