我的应用程序支持API 10级(姜饼)以上。其中一个活动绘制了一个图表,该图表在以后的版本中非常适用,但当运行10级模拟器时,我会收到一个额外的调用View.onDraw,但画布ID错误,这会导致屏幕变为空白。(这不仅仅是模拟器——有人在他们的姜饼手机上运行时报告了这个问题。)
正常的操作是对onDraw调用两次-第一次是从框架中调用,我从中获取画布ID,第二次是从我对invalidate()的调用中调用,它传递相同的画布ID。这两次调用发生在10级模拟器中,但第三次调用具有不同的画布ID,即不属于视图,这会将其清空。
该活动源于SherlockActivity,以提供一个操作栏,我相信这就是问题的原因。
我的活动类的相关代码:
public class Chart extends SherlockActivity implements OnGestureListener, OnDoubleTapListener, OnScaleGestureListener
{
public static boolean mDataSet = false;
private ChartView mView;
private Menu mMenu;
private GestureDetector mDetector;
private ScaleGestureDetector mScaleDetector;
private ActionBar mActionBar;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mDataSet = false;
mActionBar = getSupportActionBar();
mActionBar.setHomeButtonEnabled(true);
mActionBar.setDisplayHomeAsUpEnabled(true);
mActionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
mView = new ChartView(this, mCentreLat, mCentreLong, mRadius);
setContentView(mView);
setTitle("");
Context context = getApplicationContext();
mDetector = new GestureDetector(context, this);
mScaleDetector = new ScaleGestureDetector(context, this);
}
@Override
public void onConfigurationChanged(Configuration config)
{
super.onConfigurationChanged(config);
mDataSet = false;
}
// Menu handling
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
mMenu = menu;
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.chart_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
boolean handled = true;
switch (item.getItemId())
{
case android.R.id.home:
finish();
break;
case R.id.viewOptions:
mDataSet = false;
Intent i = new Intent(getBaseContext(), ChartSettings.class);
startActivity(i);
break;
// Other menu options here...
default:
handled = false;
}
return handled;
}
我的View类中的相关代码:
public class ChartView extends View
{
public ChartView(Context context, float centreLat, float centreLong, float radius)
{
super(context);
mContext = context;
mCentreLat = centreLat;
mCentreLong = centreLong;
mRadius = radius;
}
@Override
protected void onDraw(Canvas canvas)
{
// First time
// (We pick up the canvas id mCanvas from the parameter.)
// (Nothing much else relevant here, except this is where stuff
// gets initialized, then in setDataInfo(), mDataSet is set true
// and invalidate() is called at the end.)
if (!Chart.mDataSet)
{
setBackgroundColor(Color.WHITE);
mCanvas = canvas;
initPaint();
setDataInfo(); // invalidate() called at end
}
else
{
// Second call to onDraw() with same canvas id comes here,
// then an unwanted third call with a different canvas id, only
// with the Level 10 (Gingerbread) emulator.
// This is where the various lines and shapes are plotted
// on the canvas (mCanvas)
plotLinesAndShapes();
}
请有人解释为什么第三次通话是用姜饼模拟器(或手机)进行的吗?其效果是屏幕被覆盖(完全变白)。
当它到达这个函数时,已经太晚了,调用不能被忽略——随着调用堆栈的展开,屏幕变为空白。
有一个工作循环-如果用户从菜单中选择视图选项,然后立即返回到图表,它将被重新绘制,从那时起行为正常。
问题是您保留了对作为参数接收的Canvas的引用。无法保证此Canvas实例在当前帧完成后有效。例如,您可以在每个帧上接收不同的Canvas实例。当视图渲染为位图时,通常会收到不同的Canvas(例如View.setDrawingCacheEnabled())
不要在mCanvas中保留引用,只需将收到的画布传递给plotLinesAndShapes()即可。