实现 AsyncTask 时返回空指针引用
back press on a null pointer reference when implemented AsyncTask
我创建了一个名为 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();
}
}
而内class 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);
我想在 onstop()
期间取消我的 AsyncTask
但这似乎不起作用。有人对我能做什么有什么建议吗?
更新:
按照这个 post, I was able to follow the LunarLander 示例并实施 new Runnable()
来实现我需要的。
您正在从不推荐的单独线程访问 UI 元素。 NullPointerException
非常简单。当您使用后退按钮完成 activity 时,myCanvas = getHolder().lockCanvas();
正在设置对 myCanvas
属性的空引用。
如果代码在您的 UI 线程内(即在您的 activity 生命周期中的任何函数内),这可以由 activity 生命周期处理onStop
或 onDestroy
等函数。但是,您正试图从 UI 线程之外的单独线程更改 UI 元素(在您的情况下为 myCanvas
),该线程超出了 Activity
资源管理范围。因此,getHolder().lockCanvas()
获得了 canvas 的空引用,而您在绘图时获得了 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
}
}
并且在您的 activity 中启动 AsyncTask
时,不要忘记为其分配侦听器。
MultiplyTask task = new MultiplyTask();
task.listener = this;
task.execute();
代码未经测试,可能包含错误。请根据您的需要进行修改。我想你已经明白了。
我创建了一个名为 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();
}
}
而内class 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);
我想在 onstop()
期间取消我的 AsyncTask
但这似乎不起作用。有人对我能做什么有什么建议吗?
更新:
按照这个 post, I was able to follow the LunarLander 示例并实施 new Runnable()
来实现我需要的。
您正在从不推荐的单独线程访问 UI 元素。 NullPointerException
非常简单。当您使用后退按钮完成 activity 时,myCanvas = getHolder().lockCanvas();
正在设置对 myCanvas
属性的空引用。
如果代码在您的 UI 线程内(即在您的 activity 生命周期中的任何函数内),这可以由 activity 生命周期处理onStop
或 onDestroy
等函数。但是,您正试图从 UI 线程之外的单独线程更改 UI 元素(在您的情况下为 myCanvas
),该线程超出了 Activity
资源管理范围。因此,getHolder().lockCanvas()
获得了 canvas 的空引用,而您在绘图时获得了 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
}
}
并且在您的 activity 中启动 AsyncTask
时,不要忘记为其分配侦听器。
MultiplyTask task = new MultiplyTask();
task.listener = this;
task.execute();
代码未经测试,可能包含错误。请根据您的需要进行修改。我想你已经明白了。