我创建了一个名为JoyStickView
的文件,扩展了SurfaceView
。
在我的JoyStickView.java
文件中,我有以下函数调用AsyncTask
来绘制两个操纵杆:
private void drawJoystick(float hatX, float hatY) {
// Only draw the joystick when SurfaceView has been created
if (getHolder().getSurface().isValid()) {
new MultiplyTask().execute();
}
}
内部课程AsyncTask
如下所示:
public class MultiplyTask extends AsyncTask<Void, Bitmap, Bitmap[]> {
@Override
protected void onPreExecute() {
//super.onPreExecute();
}
@Override
protected Bitmap[] doInBackground(Void... progress_data) {
Bitmap[] bitmapArray = new Bitmap[2];
bitmapArray[0] = BitmapFactory.decodeResource(getResources(), R.drawable.joystick_base);
bitmapArray[1] = BitmapFactory.decodeResource(getResources(), R.drawable.joystick_hat);
//publishProgress(bitmapArray);
return bitmapArray;
}
@Override
protected void onProgressUpdate(Bitmap... bitmapArray) {
//super.onProgressUpdate(values);\
}
@Override
protected void onPostExecute(Bitmap[] bitmapArray) {
// super.onPostExecute(s);
myCanvas = getHolder().lockCanvas();
myCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
switch (getId()) {
case R.id.joystickRight:
// draw_joystick_base(myCanvas, R.drawable.joystick_base);
float c = bitmapArray[0].getWidth() / 2;
float d = bitmapArray[0].getHeight() / 2;
myCanvas.drawBitmap(bitmapArray[0], centerX - c, centerY - d, new Paint());
break;
case R.id.joystickLeft:
// draw_joystick_base(myCanvas, R.drawable.joystick_base);
float c1 = bitmapArray[0].getWidth() / 2;
float d1 = bitmapArray[0].getHeight() / 2;
myCanvas.drawBitmap(bitmapArray[0], centerX - c1, centerY - d1, new Paint());
break;
}
float a = bitmapArray[1].getWidth() / 2;
float b = bitmapArray[1].getHeight() / 2;
myCanvas.drawBitmap(bitmapArray[1], hatX_tmp - a, hatY_tmp - b, new Paint());
getHolder().unlockCanvasAndPost(myCanvas);
// Do things like update the progress bar
}
void stopTask() {
MultiplyTask a = new MultiplyTask();
a.cancel(true);
}
}
一切正常,直到我点击后退按钮,应用程序崩溃并给我以下空指针错误。
06-03 15:06:15.505 4478-4478/com.example.android.toybot E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.toybot, PID: 4478
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int, android.graphics.PorterDuff$Mode)' on a null object reference
at com.example.android.toybot.JoyStickView$MultiplyTask.onPostExecute(JoyStickView.java:304)
at com.example.android.toybot.JoyStickView$MultiplyTask.onPostExecute(JoyStickView.java:274)
at android.os.AsyncTask.finish(AsyncTask.java:661)
at android.os.AsyncTask.-wrap1(AsyncTask.java)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:678)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5688)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:749)
JoyStickView.java:304
就是这一行:myCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
我想在AsyncTask
期间取消onstop()
,但这似乎不起作用。任何人都对我能做什么有任何建议?
更新
在post之后,我能够按照LunarLander示例并实施new Runnable()
来实现我的需求。
答案 0 :(得分:0)
您正在从不建议的单独线程访问UI元素。 NullPointerException
非常简单。使用后退按钮完成活动时,myCanvas = getHolder().lockCanvas();
正在设置myCanvas
属性的空引用。
如果代码在您的UI线程内(即在您的活动生命周期中的任何函数内),这可能由活动生命周期函数(如onStop
或onDestroy
)处理。但是,您尝试从除myCanvas
资源管理范围之外的UI线程以外的单独线程更改UI元素(在您的情况下为Activity
)。因此getHolder().lockCanvas()
获取画布的空引用,并且您在绘图上获得NullPointerException
。
通过将接口实现为AsyncTask
的侦听器,可以轻松避免这种情况,以便侦听器函数驻留在Activity
中并正确处理资源。例如,您可以考虑像这样创建interface
。
public interface MultiplyResponseReceiver {
void onMultiplyResponseReceived(Bitmap[] bitmapArray);
}
现在在AsyncTask
中使用此界面的属性。
public class MultiplyTask extends AsyncTask<Void, Bitmap, Bitmap[]> {
public MultiplyResponseReceiver listener;
@Override
protected void onPreExecute() {
//super.onPreExecute();
}
@Override
protected Bitmap[] doInBackground(Void... progress_data) {
Bitmap[] bitmapArray = new Bitmap[2];
bitmapArray[0] = BitmapFactory.decodeResource(getResources(), R.drawable.joystick_base);
bitmapArray[1] = BitmapFactory.decodeResource(getResources(), R.drawable.joystick_hat);
//publishProgress(bitmapArray);
return bitmapArray;
}
@Override
protected void onProgressUpdate(Bitmap... bitmapArray) {
//super.onProgressUpdate(values);\
}
@Override
protected void onPostExecute(Bitmap[] bitmapArray) {
// super.onPostExecute(s);
listener.onMultiplyResponseReceived(bitmapArray);
}
}
现在在Activity
中实现这样的界面。
public class YourActivity extends AppCompatActivity implements MultiplyResponseReceiver {
@Override
public void onMultiplyResponseReceived() {
myCanvas = getHolder().lockCanvas();
myCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
switch (getId()) {
case R.id.joystickRight:
// draw_joystick_base(myCanvas, R.drawable.joystick_base);
float c = bitmapArray[0].getWidth() / 2;
float d = bitmapArray[0].getHeight() / 2;
myCanvas.drawBitmap(bitmapArray[0], centerX - c, centerY - d, new Paint());
break;
case R.id.joystickLeft:
// draw_joystick_base(myCanvas, R.drawable.joystick_base);
float c1 = bitmapArray[0].getWidth() / 2;
float d1 = bitmapArray[0].getHeight() / 2;
myCanvas.drawBitmap(bitmapArray[0], centerX - c1, centerY - d1, new Paint());
break;
}
float a = bitmapArray[1].getWidth() / 2;
float b = bitmapArray[1].getHeight() / 2;
myCanvas.drawBitmap(bitmapArray[1], hatX_tmp - a, hatY_tmp - b, new Paint());
getHolder().unlockCanvasAndPost(myCanvas);
// Do things like update the progress bar
}
}
在您的活动中启动AsyncTask
时,请不要忘记将侦听器分配给它。
MultiplyTask task = new MultiplyTask();
task.listener = this;
task.execute();
代码未经过测试,可能包含错误。请根据您的需要进行修改。我想你已经有了这个想法。